diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss
index 91ce63bfe..c08588ca5 100644
--- a/installer/innosetup/setup.iss
+++ b/installer/innosetup/setup.iss
@@ -21,6 +21,7 @@
[Files]
Source: {#ReleaseDir}\Greenshot.exe; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\Greenshot.Base.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
+Source: {#ReleaseDir}\Greenshot.Editor.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 77faddc33..e56ca9d63 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -108,7 +108,7 @@
-
+
///
- private void timer_Tick(object sender, EventArgs e)
+ private void Timer_Tick(object sender, EventArgs e)
{
try
{
@@ -125,7 +131,7 @@ namespace Greenshot.Base.Controls
}
catch (Exception ex)
{
- Log.Warn("An exception occured while animating:", ex);
+ Log.Warn("An exception occurred while animating:", ex);
}
}
diff --git a/src/Greenshot.Base/Controls/QualityDialog.cs b/src/Greenshot.Base/Controls/QualityDialog.cs
index 6482a291d..2212ab35b 100644
--- a/src/Greenshot.Base/Controls/QualityDialog.cs
+++ b/src/Greenshot.Base/Controls/QualityDialog.cs
@@ -21,6 +21,7 @@
using System;
using Greenshot.Base.Core;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces.Plugin;
diff --git a/src/Greenshot.Base/Controls/SaveImageFileDialog.cs b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs
index 87185bb55..3c9b2780e 100644
--- a/src/Greenshot.Base/Controls/SaveImageFileDialog.cs
+++ b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs
@@ -23,6 +23,7 @@ using System;
using System.IO;
using System.Windows.Forms;
using Greenshot.Base.Core;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using log4net;
diff --git a/src/Greenshot.Base/Controls/ThumbnailForm.cs b/src/Greenshot.Base/Controls/ThumbnailForm.cs
index 2b5882e36..c8f22f1f1 100644
--- a/src/Greenshot.Base/Controls/ThumbnailForm.cs
+++ b/src/Greenshot.Base/Controls/ThumbnailForm.cs
@@ -23,6 +23,7 @@ using System;
using System.Drawing;
using System.Windows.Forms;
using Greenshot.Base.Core;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.UnmanagedHelpers;
using Greenshot.Base.UnmanagedHelpers.Enums;
diff --git a/src/Greenshot.Base/Core/AnimationHelpers.cs b/src/Greenshot.Base/Core/AnimationHelpers.cs
index ba4769ffa..8b58a1c34 100644
--- a/src/Greenshot.Base/Core/AnimationHelpers.cs
+++ b/src/Greenshot.Base/Core/AnimationHelpers.cs
@@ -238,19 +238,19 @@ namespace Greenshot.Base.Core
return true;
}
- if (_queue.Count > 0)
+ if (_queue.Count <= 0)
{
- First = Current;
- CurrentFrameNr = 0;
- AnimationLeg nextLeg = _queue.Dequeue();
- Last = nextLeg.Destination;
- Frames = nextLeg.Frames;
- EasingType = nextLeg.EasingType;
- EasingMode = nextLeg.EasingMode;
- return true;
+ return false;
}
+ First = Current;
+ CurrentFrameNr = 0;
+ AnimationLeg nextLeg = _queue.Dequeue();
+ Last = nextLeg.Destination;
+ Frames = nextLeg.Frames;
+ EasingType = nextLeg.EasingType;
+ EasingMode = nextLeg.EasingMode;
+ return true;
- return false;
}
}
@@ -303,20 +303,21 @@ namespace Greenshot.Base.Core
/// Rectangle
public override Rectangle Next()
{
- if (NextFrame)
+ if (!NextFrame)
{
- double easingValue = EasingValue;
- double dx = Last.X - First.X;
- double dy = Last.Y - First.Y;
-
- int x = First.X + (int) (easingValue * dx);
- int y = First.Y + (int) (easingValue * dy);
- double dw = Last.Width - First.Width;
- double dh = Last.Height - First.Height;
- int width = First.Width + (int) (easingValue * dw);
- int height = First.Height + (int) (easingValue * dh);
- Current = new Rectangle(x, y, width, height);
+ return Current;
}
+ double easingValue = EasingValue;
+ double dx = Last.X - First.X;
+ double dy = Last.Y - First.Y;
+
+ int x = First.X + (int) (easingValue * dx);
+ int y = First.Y + (int) (easingValue * dy);
+ double dw = Last.Width - First.Width;
+ double dh = Last.Height - First.Height;
+ int width = First.Width + (int) (easingValue * dw);
+ int height = First.Height + (int) (easingValue * dh);
+ Current = new Rectangle(x, y, width, height);
return Current;
}
diff --git a/src/Greenshot.Base/Core/Capture.cs b/src/Greenshot.Base/Core/Capture.cs
index efd0ed6c7..347cd0067 100644
--- a/src/Greenshot.Base/Core/Capture.cs
+++ b/src/Greenshot.Base/Core/Capture.cs
@@ -80,7 +80,7 @@ namespace Greenshot.Base.Core
}
finally
{
- // Always dispose, even when a exception occured
+ // Always dispose, even when a exception occurred
value.Dispose();
}
}
diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs
index 5275661fc..7da99f216 100644
--- a/src/Greenshot.Base/Core/ClipboardHelper.cs
+++ b/src/Greenshot.Base/Core/ClipboardHelper.cs
@@ -30,6 +30,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Plugin;
diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs
index d34a10e33..9c1fbd913 100644
--- a/src/Greenshot.Base/Core/CoreConfiguration.cs
+++ b/src/Greenshot.Base/Core/CoreConfiguration.cs
@@ -26,57 +26,12 @@ using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
namespace Greenshot.Base.Core
{
- public enum ClipboardFormat
- {
- PNG,
- DIB,
- HTML,
- HTMLDATAURL,
- BITMAP,
- DIBV5
- }
-
- public enum OutputFormat
- {
- bmp,
- gif,
- jpg,
- png,
- tiff,
- greenshot,
- ico
- }
-
- public enum WindowCaptureMode
- {
- Screen,
- GDI,
- Aero,
- AeroTransparent,
- Auto
- }
-
- public enum BuildStates
- {
- UNSTABLE,
- RELEASE_CANDIDATE,
- RELEASE
- }
-
- public enum ClickActions
- {
- DO_NOTHING,
- OPEN_LAST_IN_EXPLORER,
- OPEN_LAST_IN_EDITOR,
- OPEN_SETTINGS,
- SHOW_CONTEXT_MENU
- }
-
///
/// Description of CoreConfiguration.
///
diff --git a/src/Greenshot/Helpers/DestinationHelper.cs b/src/Greenshot.Base/Core/DestinationHelper.cs
similarity index 63%
rename from src/Greenshot/Helpers/DestinationHelper.cs
rename to src/Greenshot.Base/Core/DestinationHelper.cs
index ca4fdc44b..641b29bbc 100644
--- a/src/Greenshot/Helpers/DestinationHelper.cs
+++ b/src/Greenshot.Base/Core/DestinationHelper.cs
@@ -1,132 +1,101 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Greenshot.Base.Core;
-using Greenshot.Base.IniFile;
-using Greenshot.Base.Interfaces;
-using log4net;
-
-namespace Greenshot.Helpers
-{
- ///
- /// Description of DestinationHelper.
- ///
- public static class DestinationHelper
- {
- private static readonly ILog Log = LogManager.GetLogger(typeof(DestinationHelper));
- private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection();
-
- ///
- /// Initialize the internal destinations
- ///
- public static void RegisterInternalDestinations()
- {
- foreach (Type destinationType in InterfaceUtils.GetSubclassesOf(typeof(IDestination), true))
- {
- // Only take our own
- if (!"Greenshot.Destinations".Equals(destinationType.Namespace))
- {
- continue;
- }
-
- if (destinationType.IsAbstract) continue;
-
- IDestination destination;
- try
- {
- destination = (IDestination) Activator.CreateInstance(destinationType);
- }
- catch (Exception e)
- {
- Log.ErrorFormat("Can't create instance of {0}", destinationType);
- Log.Error(e);
- continue;
- }
-
- if (destination.IsActive)
- {
- Log.DebugFormat("Found destination {0} with designation {1}", destinationType.Name, destination.Designation);
- SimpleServiceProvider.Current.AddService(destination);
- }
- else
- {
- Log.DebugFormat("Ignoring destination {0} with designation {1}", destinationType.Name, destination.Designation);
- }
- }
- }
-
- ///
- /// Method to get all the destinations from the plugins
- ///
- /// List of IDestination
- public static IEnumerable GetAllDestinations()
- {
- return SimpleServiceProvider.Current.GetAllInstances()
- .Where(destination => destination.IsActive)
- .Where(destination => CoreConfig.ExcludeDestinations == null ||
- !CoreConfig.ExcludeDestinations.Contains(destination.Designation)).OrderBy(p => p.Priority).ThenBy(p => p.Description);
- }
-
- ///
- /// Get a destination by a designation
- ///
- /// Designation of the destination
- /// IDestination or null
- public static IDestination GetDestination(string designation)
- {
- if (designation == null)
- {
- return null;
- }
-
- foreach (IDestination destination in GetAllDestinations())
- {
- if (designation.Equals(destination.Designation))
- {
- return destination;
- }
- }
-
- return null;
- }
-
- ///
- /// A simple helper method which will call ExportCapture for the destination with the specified designation
- ///
- ///
- ///
- ///
- ///
- public static ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails)
- {
- IDestination destination = GetDestination(designation);
- if (destination != null && destination.IsActive)
- {
- return destination.ExportCapture(manuallyInitiated, surface, captureDetails);
- }
-
- return null;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Collections.Generic;
+using System.Linq;
+using Greenshot.Base.IniFile;
+using Greenshot.Base.Interfaces;
+
+namespace Greenshot.Base.Core
+{
+ ///
+ /// Helper class to simplify working with destinations.
+ ///
+ public static class DestinationHelper
+ {
+ private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection();
+
+ ///
+ /// Method to get all the destinations from the plugins
+ ///
+ /// List of IDestination
+ public static IEnumerable GetAllDestinations()
+ {
+ return SimpleServiceProvider.Current.GetAllInstances()
+ .Where(destination => destination.IsActive)
+ .Where(destination => CoreConfig.ExcludeDestinations == null ||
+ !CoreConfig.ExcludeDestinations.Contains(destination.Designation)).OrderBy(p => p.Priority).ThenBy(p => p.Description);
+ }
+
+ ///
+ /// Get a destination by a designation
+ ///
+ /// Designation of the destination
+ /// IDestination or null
+ public static IDestination GetDestination(string designation)
+ {
+ if (designation == null)
+ {
+ return null;
+ }
+
+ foreach (IDestination destination in GetAllDestinations())
+ {
+ if (designation.Equals(destination.Designation))
+ {
+ return destination;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// A simple helper method which will call ExportCapture for the destination with the specified designation
+ ///
+ ///
+ /// WellKnownDestinations
+ /// ISurface
+ /// ICaptureDetails
+ public static ExportInformation ExportCapture(bool manuallyInitiated, WellKnownDestinations designation, ISurface surface, ICaptureDetails captureDetails)
+ {
+ return ExportCapture(manuallyInitiated, designation.ToString(), surface, captureDetails);
+ }
+
+ ///
+ /// A simple helper method which will call ExportCapture for the destination with the specified designation
+ ///
+ /// bool
+ /// string
+ /// ISurface
+ /// ICaptureDetails
+ public static ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails)
+ {
+ IDestination destination = GetDestination(designation);
+ if (destination != null && destination.IsActive)
+ {
+ return destination.ExportCapture(manuallyInitiated, surface, captureDetails);
+ }
+
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Core/Enums/ClickActions.cs b/src/Greenshot.Base/Core/Enums/ClickActions.cs
new file mode 100644
index 000000000..7c7fb5ee8
--- /dev/null
+++ b/src/Greenshot.Base/Core/Enums/ClickActions.cs
@@ -0,0 +1,35 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Base.Core.Enums
+{
+ ///
+ /// This are the defined actions which can be initiated when the menu is clicked
+ ///
+ public enum ClickActions
+ {
+ DO_NOTHING,
+ OPEN_LAST_IN_EXPLORER,
+ OPEN_LAST_IN_EDITOR,
+ OPEN_SETTINGS,
+ SHOW_CONTEXT_MENU
+ }
+}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Core/Enums/ClipboardFormat.cs b/src/Greenshot.Base/Core/Enums/ClipboardFormat.cs
new file mode 100644
index 000000000..56062d820
--- /dev/null
+++ b/src/Greenshot.Base/Core/Enums/ClipboardFormat.cs
@@ -0,0 +1,36 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Base.Core.Enums
+{
+ ///
+ /// These are the supported clipboard formats
+ ///
+ public enum ClipboardFormat
+ {
+ PNG,
+ DIB,
+ HTML,
+ HTMLDATAURL,
+ BITMAP,
+ DIBV5
+ }
+}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Core/Enums/OutputFormat.cs b/src/Greenshot.Base/Core/Enums/OutputFormat.cs
new file mode 100644
index 000000000..64d8a614b
--- /dev/null
+++ b/src/Greenshot.Base/Core/Enums/OutputFormat.cs
@@ -0,0 +1,37 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Base.Core.Enums
+{
+ ///
+ /// These are the supported output formats
+ ///
+ public enum OutputFormat
+ {
+ bmp,
+ gif,
+ jpg,
+ png,
+ tiff,
+ greenshot,
+ ico
+ }
+}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Core/Enums/WindowCaptureMode.cs b/src/Greenshot.Base/Core/Enums/WindowCaptureMode.cs
new file mode 100644
index 000000000..a350e1b14
--- /dev/null
+++ b/src/Greenshot.Base/Core/Enums/WindowCaptureMode.cs
@@ -0,0 +1,35 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Base.Core.Enums
+{
+ ///
+ /// These are the possible window capture modes
+ ///
+ public enum WindowCaptureMode
+ {
+ Screen,
+ GDI,
+ Aero,
+ AeroTransparent,
+ Auto
+ }
+}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Core/FilenameHelper.cs b/src/Greenshot.Base/Core/FilenameHelper.cs
index 411fee30f..4c6864547 100644
--- a/src/Greenshot.Base/Core/FilenameHelper.cs
+++ b/src/Greenshot.Base/Core/FilenameHelper.cs
@@ -25,6 +25,7 @@ using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using log4net;
diff --git a/src/Greenshot.Base/Core/ImageOutput.cs b/src/Greenshot.Base/Core/ImageOutput.cs
index 22ac769d5..39c4896c1 100644
--- a/src/Greenshot.Base/Core/ImageOutput.cs
+++ b/src/Greenshot.Base/Core/ImageOutput.cs
@@ -32,6 +32,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Greenshot.Base.Controls;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Plugin;
diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs
index a23c938fd..91ee52de1 100644
--- a/src/Greenshot.Base/Core/WindowDetails.cs
+++ b/src/Greenshot.Base/Core/WindowDetails.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interop;
diff --git a/src/Greenshot/Help/HelpFileLoader.cs b/src/Greenshot.Base/Help/HelpFileLoader.cs
similarity index 96%
rename from src/Greenshot/Help/HelpFileLoader.cs
rename to src/Greenshot.Base/Help/HelpFileLoader.cs
index 0f9d46ac6..2c9b04b4d 100644
--- a/src/Greenshot/Help/HelpFileLoader.cs
+++ b/src/Greenshot.Base/Help/HelpFileLoader.cs
@@ -1,101 +1,101 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System.Diagnostics;
-using System.Net;
-using Greenshot.Base.Core;
-using log4net;
-
-namespace Greenshot.Help
-{
- ///
- /// Description of HelpFileLoader.
- ///
- public static class HelpFileLoader
- {
- private static readonly ILog Log = LogManager.GetLogger(typeof(HelpFileLoader));
-
- private const string ExtHelpUrl = @"https://getgreenshot.org/help/";
-
- public static void LoadHelp()
- {
- string uri = FindOnlineHelpUrl(Language.CurrentLanguage) ?? Language.HelpFilePath;
- Process.Start(uri);
- }
-
- /// URL of help file in selected ietf, or (if not present) default ietf, or null (if not present, too. probably indicating that there is no internet connection)
- private static string FindOnlineHelpUrl(string currentIETF)
- {
- string ret = null;
-
- string extHelpUrlForCurrrentIETF = ExtHelpUrl;
-
- if (!currentIETF.Equals("en-US"))
- {
- extHelpUrlForCurrrentIETF += currentIETF.ToLower() + "/";
- }
-
- HttpStatusCode? httpStatusCode = GetHttpStatus(extHelpUrlForCurrrentIETF);
- if (httpStatusCode == HttpStatusCode.OK)
- {
- ret = extHelpUrlForCurrrentIETF;
- }
- else if (httpStatusCode != null && !extHelpUrlForCurrrentIETF.Equals(ExtHelpUrl))
- {
- Log.DebugFormat("Localized online help not found at {0}, will try {1} as fallback", extHelpUrlForCurrrentIETF, ExtHelpUrl);
- httpStatusCode = GetHttpStatus(ExtHelpUrl);
- if (httpStatusCode == HttpStatusCode.OK)
- {
- ret = ExtHelpUrl;
- }
- else
- {
- Log.WarnFormat("{0} returned status {1}", ExtHelpUrl, httpStatusCode);
- }
- }
- else if (httpStatusCode == null)
- {
- Log.Info("Internet connection does not seem to be available, will load help from file system.");
- }
-
- return ret;
- }
-
- ///
- /// Retrieves HTTP status for a given url.
- ///
- /// URL for which the HTTP status is to be checked
- /// An HTTP status code, or null if there is none (probably indicating that there is no internet connection available
- private static HttpStatusCode? GetHttpStatus(string url)
- {
- try
- {
- HttpWebRequest req = NetworkHelper.CreateWebRequest(url);
- using HttpWebResponse res = (HttpWebResponse) req.GetResponse();
- return res.StatusCode;
- }
- catch (WebException e)
- {
- return ((HttpWebResponse) e.Response)?.StatusCode;
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Diagnostics;
+using System.Net;
+using Greenshot.Base.Core;
+using log4net;
+
+namespace Greenshot.Base.Help
+{
+ ///
+ /// Description of HelpFileLoader.
+ ///
+ public static class HelpFileLoader
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(HelpFileLoader));
+
+ private const string ExtHelpUrl = @"https://getgreenshot.org/help/";
+
+ public static void LoadHelp()
+ {
+ string uri = FindOnlineHelpUrl(Language.CurrentLanguage) ?? Language.HelpFilePath;
+ Process.Start(uri);
+ }
+
+ /// URL of help file in selected ietf, or (if not present) default ietf, or null (if not present, too. probably indicating that there is no internet connection)
+ private static string FindOnlineHelpUrl(string currentIETF)
+ {
+ string ret = null;
+
+ string extHelpUrlForCurrrentIETF = ExtHelpUrl;
+
+ if (!currentIETF.Equals("en-US"))
+ {
+ extHelpUrlForCurrrentIETF += currentIETF.ToLower() + "/";
+ }
+
+ HttpStatusCode? httpStatusCode = GetHttpStatus(extHelpUrlForCurrrentIETF);
+ if (httpStatusCode == HttpStatusCode.OK)
+ {
+ ret = extHelpUrlForCurrrentIETF;
+ }
+ else if (httpStatusCode != null && !extHelpUrlForCurrrentIETF.Equals(ExtHelpUrl))
+ {
+ Log.DebugFormat("Localized online help not found at {0}, will try {1} as fallback", extHelpUrlForCurrrentIETF, ExtHelpUrl);
+ httpStatusCode = GetHttpStatus(ExtHelpUrl);
+ if (httpStatusCode == HttpStatusCode.OK)
+ {
+ ret = ExtHelpUrl;
+ }
+ else
+ {
+ Log.WarnFormat("{0} returned status {1}", ExtHelpUrl, httpStatusCode);
+ }
+ }
+ else if (httpStatusCode == null)
+ {
+ Log.Info("Internet connection does not seem to be available, will load help from file system.");
+ }
+
+ return ret;
+ }
+
+ ///
+ /// Retrieves HTTP status for a given url.
+ ///
+ /// URL for which the HTTP status is to be checked
+ /// An HTTP status code, or null if there is none (probably indicating that there is no internet connection available
+ private static HttpStatusCode? GetHttpStatus(string url)
+ {
+ try
+ {
+ HttpWebRequest req = NetworkHelper.CreateWebRequest(url);
+ using HttpWebResponse res = (HttpWebResponse) req.GetResponse();
+ return res.StatusCode;
+ }
+ catch (WebException e)
+ {
+ return ((HttpWebResponse) e.Response)?.StatusCode;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Interfaces/ICaptureHelper.cs b/src/Greenshot.Base/Interfaces/ICaptureHelper.cs
new file mode 100644
index 000000000..9b15032ad
--- /dev/null
+++ b/src/Greenshot.Base/Interfaces/ICaptureHelper.cs
@@ -0,0 +1,48 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using Greenshot.Base.Core;
+using Greenshot.Base.Core.Enums;
+
+namespace Greenshot.Base.Interfaces
+{
+ ///
+ /// This is a temporary solution to provide the CaptureHelper functionality via an interface
+ ///
+ public interface ICaptureHelper
+ {
+ ///
+ ///
+ ///
+ ///
+ ///
+ WindowDetails SelectCaptureWindow(WindowDetails windowToCapture);
+
+ ///
+ /// Capture the specified window
+ ///
+ /// WindowDetails
+ /// ICapture
+ /// WindowCaptureMode
+ /// ICapture
+ ICapture CaptureWindow(WindowDetails windowToCapture, ICapture capture, WindowCaptureMode coreConfigurationWindowCaptureMode);
+ }
+}
diff --git a/src/Greenshot.Base/Interfaces/IGreenshotMainForm.cs b/src/Greenshot.Base/Interfaces/IGreenshotMainForm.cs
new file mode 100644
index 000000000..cf25d48d8
--- /dev/null
+++ b/src/Greenshot.Base/Interfaces/IGreenshotMainForm.cs
@@ -0,0 +1,46 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Windows.Forms;
+
+namespace Greenshot.Base.Interfaces
+{
+ public interface IGreenshotMainForm : IWin32Window
+ {
+ ///
+ /// Create the "capture window from list" list
+ ///
+ /// ToolStripMenuItem
+ /// EventHandler
+ void AddCaptureWindowMenuItems(ToolStripMenuItem menuItem, EventHandler eventHandler);
+
+ ///
+ /// This is called indirectly from the context menu "Preferences"
+ ///
+ void ShowSetting();
+
+ ///
+ /// Show the about window
+ ///
+ void ShowAbout();
+ }
+}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Interfaces/IServiceLocator.cs b/src/Greenshot.Base/Interfaces/IServiceLocator.cs
index cd107e707..c22e3463b 100644
--- a/src/Greenshot.Base/Interfaces/IServiceLocator.cs
+++ b/src/Greenshot.Base/Interfaces/IServiceLocator.cs
@@ -1,14 +1,58 @@
-using System.Collections.Generic;
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+using System.Collections.Generic;
namespace Greenshot.Base.Interfaces
{
+ ///
+ /// This is the interface of the service locator
+ ///
public interface IServiceLocator
{
+ ///
+ /// Get all instances of the specified service
+ ///
+ /// Service to find
+ /// IEnumerable{TService}
IEnumerable GetAllInstances();
+
+ ///
+ /// Get the only instance of the specified service
+ ///
+ /// Service to find
+ /// TService
TService GetInstance();
+ ///
+ /// Add one of more services to the registry
+ ///
+ /// Type of the service
+ /// One or more services which need to be added
void AddService(params TService[] services);
+ ///
+ /// Add multiple services to the registry
+ ///
+ /// Type of the service
+ /// IEnumerable{TService} with services to add
void AddService(IEnumerable services);
}
}
\ No newline at end of file
diff --git a/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs
index 82946acdd..ef2a58e2f 100644
--- a/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs
+++ b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Greenshot.Base.Core;
+using Greenshot.Base.Core.Enums;
using Greenshot.Base.Effects;
using Greenshot.Base.IniFile;
diff --git a/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs b/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs
index 878242803..310864c75 100644
--- a/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs
+++ b/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs
@@ -64,6 +64,10 @@ namespace Greenshot.Base.UnmanagedHelpers
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
+ [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetPackageFullName(IntPtr hProcess, ref Int32 packageFullNameLength, StringBuilder fullName);
+
+
///
/// Method to get the process path
///
diff --git a/src/Greenshot.Base/WellKnownDestinations.cs b/src/Greenshot.Base/WellKnownDestinations.cs
new file mode 100644
index 000000000..029305363
--- /dev/null
+++ b/src/Greenshot.Base/WellKnownDestinations.cs
@@ -0,0 +1,36 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Base
+{
+ ///
+ /// This contains all the well known destinations, make it possible to find them via the service locator
+ ///
+ public enum WellKnownDestinations
+ {
+ Clipboard,
+ EMail,
+ FileDialog,
+ FileNoDialog,
+ Picker,
+ Printer
+ }
+}
diff --git a/src/Greenshot/Configuration/EditorConfiguration.cs b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs
similarity index 96%
rename from src/Greenshot/Configuration/EditorConfiguration.cs
rename to src/Greenshot.Editor/Configuration/EditorConfiguration.cs
index c2a252611..91a5bc335 100644
--- a/src/Greenshot/Configuration/EditorConfiguration.cs
+++ b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs
@@ -1,181 +1,181 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using Greenshot.Base.Effects;
-using Greenshot.Base.IniFile;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Base.UnmanagedHelpers.Enums;
-using Greenshot.Base.UnmanagedHelpers.Structs;
-using Greenshot.Drawing.Fields;
-
-namespace Greenshot.Configuration
-{
- ///
- /// Description of CoreConfiguration.
- ///
- [IniSection("Editor", Description = "Greenshot editor configuration")]
- public class EditorConfiguration : IniSection
- {
- [IniProperty("RecentColors", Separator = "|", Description = "Last used colors")]
- public List RecentColors { get; set; }
-
- [IniProperty("LastFieldValue", Separator = "|", Description = "Field values, make sure the last used settings are re-used")]
- public Dictionary LastUsedFieldValues { get; set; }
-
- [IniProperty("MatchSizeToCapture", Description = "Match the editor window size to the capture", DefaultValue = "True")]
- public bool MatchSizeToCapture { get; set; }
-
- [IniProperty("WindowPlacementFlags", Description = "Placement flags", DefaultValue = "0")]
- public WindowPlacementFlags WindowPlacementFlags { get; set; }
-
- [IniProperty("WindowShowCommand", Description = "Show command", DefaultValue = "Normal")]
- public ShowWindowCommand ShowWindowCommand { get; set; }
-
- [IniProperty("WindowMinPosition", Description = "Position of minimized window", DefaultValue = "-1,-1")]
- public Point WindowMinPosition { get; set; }
-
- [IniProperty("WindowMaxPosition", Description = "Position of maximized window", DefaultValue = "-1,-1")]
- public Point WindowMaxPosition { get; set; }
-
- [IniProperty("WindowNormalPosition", Description = "Position of normal window", DefaultValue = "100,100,400,400")]
- public Rectangle WindowNormalPosition { get; set; }
-
- [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")]
- public bool ReuseEditor { get; set; }
-
- [IniProperty("FreehandSensitivity",
- Description =
- "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.",
- DefaultValue = "3")]
- public int FreehandSensitivity { get; set; }
-
- [IniProperty("SuppressSaveDialogAtClose", Description = "Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue = "False")]
- public bool SuppressSaveDialogAtClose { get; set; }
-
- [IniProperty("DropShadowEffectSettings", Description = "Settings for the drop shadow effect.")]
- public DropShadowEffect DropShadowEffectSettings { get; set; }
-
- [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")]
- public TornEdgeEffect TornEdgeEffectSettings { get; set; }
-
- public override void AfterLoad()
- {
- base.AfterLoad();
- if (RecentColors == null)
- {
- RecentColors = new List();
- }
- }
-
- /// Type of the class for which to create the field
- /// FieldType of the field to construct
- ///
- /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope
- public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue)
- {
- string requestingTypeName = requestingType.Name;
- string requestedField = requestingTypeName + "." + fieldType.Name;
- object fieldValue = preferredDefaultValue;
-
- // Check if the configuration exists
- if (LastUsedFieldValues == null)
- {
- LastUsedFieldValues = new Dictionary();
- }
-
- // Check if settings for the requesting type exist, if not create!
- if (LastUsedFieldValues.ContainsKey(requestedField))
- {
- // Check if a value is set (not null)!
- if (LastUsedFieldValues[requestedField] != null)
- {
- fieldValue = LastUsedFieldValues[requestedField];
- }
- else
- {
- // Overwrite null value
- LastUsedFieldValues[requestedField] = fieldValue;
- }
- }
- else
- {
- LastUsedFieldValues.Add(requestedField, fieldValue);
- }
-
- return new Field(fieldType, requestingType)
- {
- Value = fieldValue
- };
- }
-
- public void UpdateLastFieldValue(IField field)
- {
- string requestedField = field.Scope + "." + field.FieldType.Name;
- // Check if the configuration exists
- if (LastUsedFieldValues == null)
- {
- LastUsedFieldValues = new Dictionary();
- }
-
- // check if settings for the requesting type exist, if not create!
- if (LastUsedFieldValues.ContainsKey(requestedField))
- {
- LastUsedFieldValues[requestedField] = field.Value;
- }
- else
- {
- LastUsedFieldValues.Add(requestedField, field.Value);
- }
- }
-
- public void ResetEditorPlacement()
- {
- WindowNormalPosition = new Rectangle(100, 100, 400, 400);
- WindowMaxPosition = new Point(-1, -1);
- WindowMinPosition = new Point(-1, -1);
- WindowPlacementFlags = 0;
- ShowWindowCommand = ShowWindowCommand.Normal;
- }
-
- public WindowPlacement GetEditorPlacement()
- {
- WindowPlacement placement = WindowPlacement.Default;
- placement.NormalPosition = new RECT(WindowNormalPosition);
- placement.MaxPosition = new POINT(WindowMaxPosition);
- placement.MinPosition = new POINT(WindowMinPosition);
- placement.ShowCmd = ShowWindowCommand;
- placement.Flags = WindowPlacementFlags;
- return placement;
- }
-
- public void SetEditorPlacement(WindowPlacement placement)
- {
- WindowNormalPosition = placement.NormalPosition.ToRectangle();
- WindowMaxPosition = placement.MaxPosition.ToPoint();
- WindowMinPosition = placement.MinPosition.ToPoint();
- ShowWindowCommand = placement.ShowCmd;
- WindowPlacementFlags = placement.Flags;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using Greenshot.Base.Effects;
+using Greenshot.Base.IniFile;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Base.UnmanagedHelpers.Enums;
+using Greenshot.Base.UnmanagedHelpers.Structs;
+using Greenshot.Editor.Drawing.Fields;
+
+namespace Greenshot.Editor.Configuration
+{
+ ///
+ /// Description of CoreConfiguration.
+ ///
+ [IniSection("Editor", Description = "Greenshot editor configuration")]
+ public class EditorConfiguration : IniSection
+ {
+ [IniProperty("RecentColors", Separator = "|", Description = "Last used colors")]
+ public List RecentColors { get; set; }
+
+ [IniProperty("LastFieldValue", Separator = "|", Description = "Field values, make sure the last used settings are re-used")]
+ public Dictionary LastUsedFieldValues { get; set; }
+
+ [IniProperty("MatchSizeToCapture", Description = "Match the editor window size to the capture", DefaultValue = "True")]
+ public bool MatchSizeToCapture { get; set; }
+
+ [IniProperty("WindowPlacementFlags", Description = "Placement flags", DefaultValue = "0")]
+ public WindowPlacementFlags WindowPlacementFlags { get; set; }
+
+ [IniProperty("WindowShowCommand", Description = "Show command", DefaultValue = "Normal")]
+ public ShowWindowCommand ShowWindowCommand { get; set; }
+
+ [IniProperty("WindowMinPosition", Description = "Position of minimized window", DefaultValue = "-1,-1")]
+ public Point WindowMinPosition { get; set; }
+
+ [IniProperty("WindowMaxPosition", Description = "Position of maximized window", DefaultValue = "-1,-1")]
+ public Point WindowMaxPosition { get; set; }
+
+ [IniProperty("WindowNormalPosition", Description = "Position of normal window", DefaultValue = "100,100,400,400")]
+ public Rectangle WindowNormalPosition { get; set; }
+
+ [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")]
+ public bool ReuseEditor { get; set; }
+
+ [IniProperty("FreehandSensitivity",
+ Description =
+ "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.",
+ DefaultValue = "3")]
+ public int FreehandSensitivity { get; set; }
+
+ [IniProperty("SuppressSaveDialogAtClose", Description = "Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue = "False")]
+ public bool SuppressSaveDialogAtClose { get; set; }
+
+ [IniProperty("DropShadowEffectSettings", Description = "Settings for the drop shadow effect.")]
+ public DropShadowEffect DropShadowEffectSettings { get; set; }
+
+ [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")]
+ public TornEdgeEffect TornEdgeEffectSettings { get; set; }
+
+ public override void AfterLoad()
+ {
+ base.AfterLoad();
+ if (RecentColors == null)
+ {
+ RecentColors = new List();
+ }
+ }
+
+ /// Type of the class for which to create the field
+ /// FieldType of the field to construct
+ ///
+ /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope
+ public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue)
+ {
+ string requestingTypeName = requestingType.Name;
+ string requestedField = requestingTypeName + "." + fieldType.Name;
+ object fieldValue = preferredDefaultValue;
+
+ // Check if the configuration exists
+ if (LastUsedFieldValues == null)
+ {
+ LastUsedFieldValues = new Dictionary();
+ }
+
+ // Check if settings for the requesting type exist, if not create!
+ if (LastUsedFieldValues.ContainsKey(requestedField))
+ {
+ // Check if a value is set (not null)!
+ if (LastUsedFieldValues[requestedField] != null)
+ {
+ fieldValue = LastUsedFieldValues[requestedField];
+ }
+ else
+ {
+ // Overwrite null value
+ LastUsedFieldValues[requestedField] = fieldValue;
+ }
+ }
+ else
+ {
+ LastUsedFieldValues.Add(requestedField, fieldValue);
+ }
+
+ return new Field(fieldType, requestingType)
+ {
+ Value = fieldValue
+ };
+ }
+
+ public void UpdateLastFieldValue(IField field)
+ {
+ string requestedField = field.Scope + "." + field.FieldType.Name;
+ // Check if the configuration exists
+ if (LastUsedFieldValues == null)
+ {
+ LastUsedFieldValues = new Dictionary();
+ }
+
+ // check if settings for the requesting type exist, if not create!
+ if (LastUsedFieldValues.ContainsKey(requestedField))
+ {
+ LastUsedFieldValues[requestedField] = field.Value;
+ }
+ else
+ {
+ LastUsedFieldValues.Add(requestedField, field.Value);
+ }
+ }
+
+ public void ResetEditorPlacement()
+ {
+ WindowNormalPosition = new Rectangle(100, 100, 400, 400);
+ WindowMaxPosition = new Point(-1, -1);
+ WindowMinPosition = new Point(-1, -1);
+ WindowPlacementFlags = 0;
+ ShowWindowCommand = ShowWindowCommand.Normal;
+ }
+
+ public WindowPlacement GetEditorPlacement()
+ {
+ WindowPlacement placement = WindowPlacement.Default;
+ placement.NormalPosition = new RECT(WindowNormalPosition);
+ placement.MaxPosition = new POINT(WindowMaxPosition);
+ placement.MinPosition = new POINT(WindowMinPosition);
+ placement.ShowCmd = ShowWindowCommand;
+ placement.Flags = WindowPlacementFlags;
+ return placement;
+ }
+
+ public void SetEditorPlacement(WindowPlacement placement)
+ {
+ WindowNormalPosition = placement.NormalPosition.ToRectangle();
+ WindowMaxPosition = placement.MaxPosition.ToPoint();
+ WindowMinPosition = placement.MinPosition.ToPoint();
+ ShowWindowCommand = placement.ShowCmd;
+ WindowPlacementFlags = placement.Flags;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot.Editor/Configuration/LanguageKeys.cs b/src/Greenshot.Editor/Configuration/LanguageKeys.cs
new file mode 100644
index 000000000..f15b113d4
--- /dev/null
+++ b/src/Greenshot.Editor/Configuration/LanguageKeys.cs
@@ -0,0 +1,82 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Diagnostics.CodeAnalysis;
+
+namespace Greenshot.Editor.Configuration
+{
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum LangKey
+ {
+ none,
+ contextmenu_capturefullscreen_all,
+ contextmenu_capturefullscreen_left,
+ contextmenu_capturefullscreen_top,
+ contextmenu_capturefullscreen_right,
+ contextmenu_capturefullscreen_bottom,
+ contextmenu_captureie,
+ editor_clipboardfailed,
+ editor_close_on_save,
+ editor_close_on_save_title,
+ editor_copytoclipboard,
+ editor_cuttoclipboard,
+ editor_deleteelement,
+ editor_downonelevel,
+ editor_downtobottom,
+ editor_duplicate,
+ editor_email,
+ editor_imagesaved,
+ editor_title,
+ editor_uponelevel,
+ editor_uptotop,
+ editor_undo,
+ editor_redo,
+ editor_resetsize,
+ error,
+ error_multipleinstances,
+ error_openfile,
+ error_openlink,
+ error_save,
+ error_save_invalid_chars,
+ print_error,
+ quicksettings_destination_file,
+ settings_destination,
+ settings_destination_clipboard,
+ settings_destination_editor,
+ settings_destination_fileas,
+ settings_destination_printer,
+ settings_destination_picker,
+ settings_filenamepattern,
+ settings_message_filenamepattern,
+ settings_printoptions,
+ settings_tooltip_filenamepattern,
+ settings_tooltip_language,
+ settings_tooltip_primaryimageformat,
+ settings_tooltip_storagelocation,
+ settings_visualization,
+ settings_window_capture_mode,
+ tooltip_firststart,
+ warning,
+ warning_hotkeys,
+ wait_ie_capture,
+ update_found
+ }
+}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/BindableToolStripButton.cs b/src/Greenshot.Editor/Controls/BindableToolStripButton.cs
similarity index 95%
rename from src/Greenshot/Controls/BindableToolStripButton.cs
rename to src/Greenshot.Editor/Controls/BindableToolStripButton.cs
index 603ec3499..a79d6c801 100644
--- a/src/Greenshot/Controls/BindableToolStripButton.cs
+++ b/src/Greenshot.Editor/Controls/BindableToolStripButton.cs
@@ -1,49 +1,49 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Windows.Forms;
-using Greenshot.Base.Controls;
-
-namespace Greenshot.Controls
-{
- ///
- /// Description of BindableToolStripButton.
- ///
- public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
- public string LanguageKey { get; set; }
-
- public BindableToolStripButton()
- {
- CheckedChanged += BindableToolStripButton_CheckedChanged;
- }
-
- private void BindableToolStripButton_CheckedChanged(object sender, EventArgs e)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Checked"));
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+using Greenshot.Base.Controls;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// Description of BindableToolStripButton.
+ ///
+ public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
+ public string LanguageKey { get; set; }
+
+ public BindableToolStripButton()
+ {
+ CheckedChanged += BindableToolStripButton_CheckedChanged;
+ }
+
+ private void BindableToolStripButton_CheckedChanged(object sender, EventArgs e)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Checked"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/BindableToolStripComboBox.cs b/src/Greenshot.Editor/Controls/BindableToolStripComboBox.cs
similarity index 96%
rename from src/Greenshot/Controls/BindableToolStripComboBox.cs
rename to src/Greenshot.Editor/Controls/BindableToolStripComboBox.cs
index f13cfa4d6..ac56641f1 100644
--- a/src/Greenshot/Controls/BindableToolStripComboBox.cs
+++ b/src/Greenshot.Editor/Controls/BindableToolStripComboBox.cs
@@ -1,49 +1,49 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Windows.Forms;
-using Greenshot.Base.Controls;
-
-namespace Greenshot.Controls
-{
- ///
- /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding
- ///
- public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged, IGreenshotLanguageBindable
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
- public string LanguageKey { get; set; }
-
- public BindableToolStripComboBox()
- {
- SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged;
- }
-
- private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedItem"));
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+using Greenshot.Base.Controls;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding
+ ///
+ public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged, IGreenshotLanguageBindable
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
+ public string LanguageKey { get; set; }
+
+ public BindableToolStripComboBox()
+ {
+ SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged;
+ }
+
+ private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedItem"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/BindableToolStripDropDownButton.cs b/src/Greenshot.Editor/Controls/BindableToolStripDropDownButton.cs
similarity index 96%
rename from src/Greenshot/Controls/BindableToolStripDropDownButton.cs
rename to src/Greenshot.Editor/Controls/BindableToolStripDropDownButton.cs
index 6a7affcc8..7d0a45676 100644
--- a/src/Greenshot/Controls/BindableToolStripDropDownButton.cs
+++ b/src/Greenshot.Editor/Controls/BindableToolStripDropDownButton.cs
@@ -1,82 +1,82 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System.ComponentModel;
-using System.Windows.Forms;
-using Greenshot.Base.Controls;
-
-namespace Greenshot.Controls
-{
- ///
- /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding.
- /// Also, when a DropDownItem is selected, the DropDownButton adopts its Tag and Image.
- /// The selected tag can be accessed via SelectedTag property.
- ///
- public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged, IGreenshotLanguageBindable
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
- public string LanguageKey { get; set; }
-
- public object SelectedTag
- {
- get
- {
- if (Tag == null && DropDownItems.Count > 0) Tag = DropDownItems[0].Tag;
- return Tag;
- }
- set { AdoptFromTag(value); }
- }
-
- protected override void OnDropDownItemClicked(ToolStripItemClickedEventArgs e)
- {
- ToolStripItem clickedItem = e.ClickedItem;
- if (Tag == null || !Tag.Equals(clickedItem.Tag))
- {
- Tag = clickedItem.Tag;
- Image = clickedItem.Image;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag"));
- }
-
- base.OnDropDownItemClicked(e);
- }
-
- private void AdoptFromTag(object tag)
- {
- if (Tag == null || !Tag.Equals(tag))
- {
- Tag = tag;
- foreach (ToolStripItem item in DropDownItems)
- {
- if (item.Tag != null && item.Tag.Equals(tag))
- {
- Image = item.Image;
- break;
- }
- }
-
- Tag = tag;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag"));
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.ComponentModel;
+using System.Windows.Forms;
+using Greenshot.Base.Controls;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding.
+ /// Also, when a DropDownItem is selected, the DropDownButton adopts its Tag and Image.
+ /// The selected tag can be accessed via SelectedTag property.
+ ///
+ public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged, IGreenshotLanguageBindable
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
+ public string LanguageKey { get; set; }
+
+ public object SelectedTag
+ {
+ get
+ {
+ if (Tag == null && DropDownItems.Count > 0) Tag = DropDownItems[0].Tag;
+ return Tag;
+ }
+ set { AdoptFromTag(value); }
+ }
+
+ protected override void OnDropDownItemClicked(ToolStripItemClickedEventArgs e)
+ {
+ ToolStripItem clickedItem = e.ClickedItem;
+ if (Tag == null || !Tag.Equals(clickedItem.Tag))
+ {
+ Tag = clickedItem.Tag;
+ Image = clickedItem.Image;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag"));
+ }
+
+ base.OnDropDownItemClicked(e);
+ }
+
+ private void AdoptFromTag(object tag)
+ {
+ if (Tag == null || !Tag.Equals(tag))
+ {
+ Tag = tag;
+ foreach (ToolStripItem item in DropDownItems)
+ {
+ if (item.Tag != null && item.Tag.Equals(tag))
+ {
+ Image = item.Image;
+ break;
+ }
+ }
+
+ Tag = tag;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag"));
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/ColorButton.cs b/src/Greenshot.Editor/Controls/ColorButton.cs
similarity index 94%
rename from src/Greenshot/Controls/ColorButton.cs
rename to src/Greenshot.Editor/Controls/ColorButton.cs
index 93cf4edf3..849395330 100644
--- a/src/Greenshot/Controls/ColorButton.cs
+++ b/src/Greenshot.Editor/Controls/ColorButton.cs
@@ -1,99 +1,99 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Windows.Forms;
-using Greenshot.Base.Controls;
-using ColorDialog = Greenshot.Forms.ColorDialog;
-
-namespace Greenshot.Controls
-{
- ///
- /// Description of ColorButton.
- ///
- public class ColorButton : Button, IGreenshotLanguageBindable
- {
- public event PropertyChangedEventHandler PropertyChanged;
- private Color _selectedColor = Color.White;
-
- [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
- public string LanguageKey { get; set; }
-
- public ColorButton()
- {
- Click += ColorButtonClick;
- }
-
- public Color SelectedColor
- {
- get { return _selectedColor; }
- set
- {
- _selectedColor = value;
-
- Brush brush;
- if (value != Color.Transparent)
- {
- brush = new SolidBrush(value);
- }
- else
- {
- brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray);
- }
-
- if (Image != null)
- {
- using Graphics graphics = Graphics.FromImage(Image);
- graphics.FillRectangle(brush, new Rectangle(4, 17, 16, 3));
- }
-
- // cleanup GDI Object
- brush.Dispose();
- Invalidate();
- }
- }
-
- private void ColorButtonClick(object sender, EventArgs e)
- {
- var colorDialog = new ColorDialog
- {
- Color = SelectedColor
- };
- // Using the parent to make sure the dialog doesn't show on another window
- colorDialog.ShowDialog(Parent.Parent);
- if (colorDialog.DialogResult == DialogResult.Cancel)
- {
- return;
- }
-
- if (colorDialog.Color.Equals(SelectedColor))
- {
- return;
- }
-
- SelectedColor = colorDialog.Color;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor"));
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using Greenshot.Base.Controls;
+using ColorDialog = Greenshot.Editor.Forms.ColorDialog;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// Description of ColorButton.
+ ///
+ public class ColorButton : Button, IGreenshotLanguageBindable
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ private Color _selectedColor = Color.White;
+
+ [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
+ public string LanguageKey { get; set; }
+
+ public ColorButton()
+ {
+ Click += ColorButtonClick;
+ }
+
+ public Color SelectedColor
+ {
+ get { return _selectedColor; }
+ set
+ {
+ _selectedColor = value;
+
+ Brush brush;
+ if (value != Color.Transparent)
+ {
+ brush = new SolidBrush(value);
+ }
+ else
+ {
+ brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray);
+ }
+
+ if (Image != null)
+ {
+ using Graphics graphics = Graphics.FromImage(Image);
+ graphics.FillRectangle(brush, new Rectangle(4, 17, 16, 3));
+ }
+
+ // cleanup GDI Object
+ brush.Dispose();
+ Invalidate();
+ }
+ }
+
+ private void ColorButtonClick(object sender, EventArgs e)
+ {
+ var colorDialog = new ColorDialog
+ {
+ Color = SelectedColor
+ };
+ // Using the parent to make sure the dialog doesn't show on another window
+ colorDialog.ShowDialog(Parent.Parent);
+ if (colorDialog.DialogResult == DialogResult.Cancel)
+ {
+ return;
+ }
+
+ if (colorDialog.Color.Equals(SelectedColor))
+ {
+ return;
+ }
+
+ SelectedColor = colorDialog.Color;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/src/Greenshot.Editor/Controls/CustomToolStripProfessionalRenderer.cs
similarity index 96%
rename from src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs
rename to src/Greenshot.Editor/Controls/CustomToolStripProfessionalRenderer.cs
index 8c8927508..578aaf655 100644
--- a/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs
+++ b/src/Greenshot.Editor/Controls/CustomToolStripProfessionalRenderer.cs
@@ -1,84 +1,84 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System.Drawing;
-using System.Windows.Forms;
-
-namespace Greenshot.Controls
-{
- ///
- /// Prevent having a gradient background in the toolstrip, and the overflow button
- /// See: https://stackoverflow.com/a/16926979
- ///
- internal class CustomProfessionalColorTable : ProfessionalColorTable
- {
- public override Color ToolStripGradientBegin
- {
- get { return SystemColors.Control; }
- }
-
- public override Color ToolStripGradientMiddle
- {
- get { return SystemColors.Control; }
- }
-
- public override Color ToolStripGradientEnd
- {
- get { return SystemColors.Control; }
- }
-
- public override Color OverflowButtonGradientBegin
- {
- get { return SystemColors.Control; }
- }
-
- public override Color OverflowButtonGradientMiddle
- {
- get { return SystemColors.Control; }
- }
-
- public override Color OverflowButtonGradientEnd
- {
- get { return SystemColors.Control; }
- }
- }
-
- ///
- /// ToolStripProfessionalRenderer without having a visual artifact
- /// See: https://stackoverflow.com/a/16926979 and https://stackoverflow.com/a/13418840
- ///
- public class CustomToolStripProfessionalRenderer : ToolStripProfessionalRenderer
- {
- public CustomToolStripProfessionalRenderer() : base(new CustomProfessionalColorTable())
- {
- RoundedEdges = false;
- }
-
- ///
- /// By overriding the OnRenderToolStripBorder we can make the ToolStrip without border
- ///
- ///
- protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
- {
- // Don't draw a border
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// Prevent having a gradient background in the toolstrip, and the overflow button
+ /// See: https://stackoverflow.com/a/16926979
+ ///
+ internal class CustomProfessionalColorTable : ProfessionalColorTable
+ {
+ public override Color ToolStripGradientBegin
+ {
+ get { return SystemColors.Control; }
+ }
+
+ public override Color ToolStripGradientMiddle
+ {
+ get { return SystemColors.Control; }
+ }
+
+ public override Color ToolStripGradientEnd
+ {
+ get { return SystemColors.Control; }
+ }
+
+ public override Color OverflowButtonGradientBegin
+ {
+ get { return SystemColors.Control; }
+ }
+
+ public override Color OverflowButtonGradientMiddle
+ {
+ get { return SystemColors.Control; }
+ }
+
+ public override Color OverflowButtonGradientEnd
+ {
+ get { return SystemColors.Control; }
+ }
+ }
+
+ ///
+ /// ToolStripProfessionalRenderer without having a visual artifact
+ /// See: https://stackoverflow.com/a/16926979 and https://stackoverflow.com/a/13418840
+ ///
+ public class CustomToolStripProfessionalRenderer : ToolStripProfessionalRenderer
+ {
+ public CustomToolStripProfessionalRenderer() : base(new CustomProfessionalColorTable())
+ {
+ RoundedEdges = false;
+ }
+
+ ///
+ /// By overriding the OnRenderToolStripBorder we can make the ToolStrip without border
+ ///
+ ///
+ protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
+ {
+ // Don't draw a border
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/FontFamilyComboBox.cs b/src/Greenshot.Editor/Controls/FontFamilyComboBox.cs
similarity index 97%
rename from src/Greenshot/Controls/FontFamilyComboBox.cs
rename to src/Greenshot.Editor/Controls/FontFamilyComboBox.cs
index 6369f83e4..b57d52e75 100644
--- a/src/Greenshot/Controls/FontFamilyComboBox.cs
+++ b/src/Greenshot.Editor/Controls/FontFamilyComboBox.cs
@@ -1,141 +1,141 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using System.Windows.Forms;
-
-namespace Greenshot.Controls
-{
- ///
- /// ToolStripComboBox containing installed font families,
- /// implementing INotifyPropertyChanged for data binding
- ///
- public class FontFamilyComboBox : ToolStripComboBox, INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- public FontFamily FontFamily
- {
- get { return (FontFamily) SelectedItem; }
- set
- {
- if (!SelectedItem.Equals(value))
- {
- SelectedItem = value;
- }
- }
- }
-
- public FontFamilyComboBox()
- {
- if (ComboBox != null)
- {
- ComboBox.DataSource = FontFamily.Families;
- ComboBox.DisplayMember = "Name";
- SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged;
- ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
- ComboBox.DrawItem += ComboBox_DrawItem;
- }
- }
-
- private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
- {
- // DrawBackground handles drawing the background (i.e,. hot-tracked v. not)
- // It uses the system colors (Bluish, and and white, by default)
- // same as calling e.Graphics.FillRectangle ( SystemBrushes.Highlight, e.Bounds );
- e.DrawBackground();
-
- if (e.Index > -1)
- {
- FontFamily fontFamily = Items[e.Index] as FontFamily;
- FontStyle fontStyle = FontStyle.Regular;
- if (fontFamily != null && !fontFamily.IsStyleAvailable(FontStyle.Regular))
- {
- if (fontFamily.IsStyleAvailable(FontStyle.Bold))
- {
- fontStyle = FontStyle.Bold;
- }
- else if (fontFamily.IsStyleAvailable(FontStyle.Italic))
- {
- fontStyle = FontStyle.Italic;
- }
- else if (fontFamily.IsStyleAvailable(FontStyle.Strikeout))
- {
- fontStyle = FontStyle.Strikeout;
- }
- else if (fontFamily.IsStyleAvailable(FontStyle.Underline))
- {
- fontStyle = FontStyle.Underline;
- }
- }
-
- try
- {
- if (fontFamily != null)
- {
- DrawText(e.Graphics, fontFamily, fontStyle, e.Bounds, fontFamily.Name);
- }
- }
- catch
- {
- // If the drawing failed, BUG-1770 seems to have a weird case that causes: Font 'Lucida Sans Typewriter' does not support style 'Regular'
- if (fontFamily != null)
- {
- DrawText(e.Graphics, FontFamily.GenericSansSerif, FontStyle.Regular, e.Bounds, fontFamily.Name);
- }
- }
- }
-
- // Uncomment this if you actually like the way the focus rectangle looks
- //e.DrawFocusRectangle ();
- }
-
- ///
- /// Helper method to draw the string
- ///
- ///
- ///
- ///
- ///
- ///
- private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text)
- {
- using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel);
- // Make sure the text is visible by centering it in the line
- using StringFormat stringFormat = new StringFormat
- {
- LineAlignment = StringAlignment.Center
- };
- graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat);
- }
-
- private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
- {
- if (PropertyChanged == null) return;
- PropertyChanged(this, new PropertyChangedEventArgs("Text"));
- PropertyChanged(this, new PropertyChangedEventArgs("FontFamily"));
- PropertyChanged(this, new PropertyChangedEventArgs("SelectedIndex"));
- PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// ToolStripComboBox containing installed font families,
+ /// implementing INotifyPropertyChanged for data binding
+ ///
+ public class FontFamilyComboBox : ToolStripComboBox, INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public FontFamily FontFamily
+ {
+ get { return (FontFamily) SelectedItem; }
+ set
+ {
+ if (!SelectedItem.Equals(value))
+ {
+ SelectedItem = value;
+ }
+ }
+ }
+
+ public FontFamilyComboBox()
+ {
+ if (ComboBox != null)
+ {
+ ComboBox.DataSource = FontFamily.Families;
+ ComboBox.DisplayMember = "Name";
+ SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged;
+ ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
+ ComboBox.DrawItem += ComboBox_DrawItem;
+ }
+ }
+
+ private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
+ {
+ // DrawBackground handles drawing the background (i.e,. hot-tracked v. not)
+ // It uses the system colors (Bluish, and and white, by default)
+ // same as calling e.Graphics.FillRectangle ( SystemBrushes.Highlight, e.Bounds );
+ e.DrawBackground();
+
+ if (e.Index > -1)
+ {
+ FontFamily fontFamily = Items[e.Index] as FontFamily;
+ FontStyle fontStyle = FontStyle.Regular;
+ if (fontFamily != null && !fontFamily.IsStyleAvailable(FontStyle.Regular))
+ {
+ if (fontFamily.IsStyleAvailable(FontStyle.Bold))
+ {
+ fontStyle = FontStyle.Bold;
+ }
+ else if (fontFamily.IsStyleAvailable(FontStyle.Italic))
+ {
+ fontStyle = FontStyle.Italic;
+ }
+ else if (fontFamily.IsStyleAvailable(FontStyle.Strikeout))
+ {
+ fontStyle = FontStyle.Strikeout;
+ }
+ else if (fontFamily.IsStyleAvailable(FontStyle.Underline))
+ {
+ fontStyle = FontStyle.Underline;
+ }
+ }
+
+ try
+ {
+ if (fontFamily != null)
+ {
+ DrawText(e.Graphics, fontFamily, fontStyle, e.Bounds, fontFamily.Name);
+ }
+ }
+ catch
+ {
+ // If the drawing failed, BUG-1770 seems to have a weird case that causes: Font 'Lucida Sans Typewriter' does not support style 'Regular'
+ if (fontFamily != null)
+ {
+ DrawText(e.Graphics, FontFamily.GenericSansSerif, FontStyle.Regular, e.Bounds, fontFamily.Name);
+ }
+ }
+ }
+
+ // Uncomment this if you actually like the way the focus rectangle looks
+ //e.DrawFocusRectangle ();
+ }
+
+ ///
+ /// Helper method to draw the string
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text)
+ {
+ using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel);
+ // Make sure the text is visible by centering it in the line
+ using StringFormat stringFormat = new StringFormat
+ {
+ LineAlignment = StringAlignment.Center
+ };
+ graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat);
+ }
+
+ private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (PropertyChanged == null) return;
+ PropertyChanged(this, new PropertyChangedEventArgs("Text"));
+ PropertyChanged(this, new PropertyChangedEventArgs("FontFamily"));
+ PropertyChanged(this, new PropertyChangedEventArgs("SelectedIndex"));
+ PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/MenuStripEx.cs b/src/Greenshot.Editor/Controls/MenuStripEx.cs
similarity index 96%
rename from src/Greenshot/Controls/MenuStripEx.cs
rename to src/Greenshot.Editor/Controls/MenuStripEx.cs
index d6264e787..9af1da2cf 100644
--- a/src/Greenshot/Controls/MenuStripEx.cs
+++ b/src/Greenshot.Editor/Controls/MenuStripEx.cs
@@ -1,65 +1,65 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Windows.Forms;
-using Greenshot.Base.UnmanagedHelpers.Enums;
-
-namespace Greenshot.Controls
-{
- ///
- /// This is an extension of the default MenuStrip and allows us to click it even when the form doesn't have focus.
- /// See: https://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx
- ///
- public class MenuStripEx : MenuStrip
- {
- private enum NativeConstants : uint
- {
- MA_ACTIVATE = 1,
- MA_ACTIVATEANDEAT = 2,
- }
-
- private bool _clickThrough;
-
- ///
- /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus.
- ///
- ///
- /// Default value is false, which is the same behavior provided by the base ToolStrip class.
- ///
- public bool ClickThrough
- {
- get { return _clickThrough; }
-
- set { _clickThrough = value; }
- }
-
- protected override void WndProc(ref Message m)
- {
- base.WndProc(ref m);
- var windowsMessage = (WindowsMessages) m.Msg;
- if (_clickThrough && windowsMessage == WindowsMessages.WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT)
- {
- m.Result = (IntPtr) NativeConstants.MA_ACTIVATE;
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Windows.Forms;
+using Greenshot.Base.UnmanagedHelpers.Enums;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// This is an extension of the default MenuStrip and allows us to click it even when the form doesn't have focus.
+ /// See: https://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx
+ ///
+ public class MenuStripEx : MenuStrip
+ {
+ private enum NativeConstants : uint
+ {
+ MA_ACTIVATE = 1,
+ MA_ACTIVATEANDEAT = 2,
+ }
+
+ private bool _clickThrough;
+
+ ///
+ /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus.
+ ///
+ ///
+ /// Default value is false, which is the same behavior provided by the base ToolStrip class.
+ ///
+ public bool ClickThrough
+ {
+ get { return _clickThrough; }
+
+ set { _clickThrough = value; }
+ }
+
+ protected override void WndProc(ref Message m)
+ {
+ base.WndProc(ref m);
+ var windowsMessage = (WindowsMessages) m.Msg;
+ if (_clickThrough && windowsMessage == WindowsMessages.WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT)
+ {
+ m.Result = (IntPtr) NativeConstants.MA_ACTIVATE;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/NonJumpingPanel.cs b/src/Greenshot.Editor/Controls/NonJumpingPanel.cs
similarity index 96%
rename from src/Greenshot/Controls/NonJumpingPanel.cs
rename to src/Greenshot.Editor/Controls/NonJumpingPanel.cs
index bb9f46d27..3ce0fbdaf 100644
--- a/src/Greenshot/Controls/NonJumpingPanel.cs
+++ b/src/Greenshot.Editor/Controls/NonJumpingPanel.cs
@@ -1,70 +1,70 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System.Drawing;
-using System.Windows.Forms;
-
-namespace Greenshot.Controls
-{
- ///
- /// See: https://nickstips.wordpress.com/2010/03/03/c-panel-resets-scroll-position-after-focus-is-lost-and-regained/
- ///
- public class NonJumpingPanel : Panel
- {
- protected override Point ScrollToControl(Control activeControl)
- {
- // Returning the current location prevents the panel from
- // scrolling to the active control when the panel loses and regains focus
- return DisplayRectangle.Location;
- }
-
- ///
- /// Add horizontal scrolling to the panel, when using the wheel and the shift key is pressed
- ///
- /// MouseEventArgs
- protected override void OnMouseWheel(MouseEventArgs e)
- {
- //Check if Scrollbars available and CTRL key pressed -> Zoom IN OUT
- if ((VScroll || HScroll) && (ModifierKeys & Keys.Control) == Keys.Control)
- {
- VScroll = false;
- HScroll = false;
- base.OnMouseWheel(e);
- VScroll = true;
- HScroll = true;
- }
- else
- {
- //Vertical Scoll with SHIFT key pressed
- if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift)
- {
- VScroll = false;
- base.OnMouseWheel(e);
- VScroll = true;
- }
- else
- {
- base.OnMouseWheel(e);
- }
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// See: https://nickstips.wordpress.com/2010/03/03/c-panel-resets-scroll-position-after-focus-is-lost-and-regained/
+ ///
+ public class NonJumpingPanel : Panel
+ {
+ protected override Point ScrollToControl(Control activeControl)
+ {
+ // Returning the current location prevents the panel from
+ // scrolling to the active control when the panel loses and regains focus
+ return DisplayRectangle.Location;
+ }
+
+ ///
+ /// Add horizontal scrolling to the panel, when using the wheel and the shift key is pressed
+ ///
+ /// MouseEventArgs
+ protected override void OnMouseWheel(MouseEventArgs e)
+ {
+ //Check if Scrollbars available and CTRL key pressed -> Zoom IN OUT
+ if ((VScroll || HScroll) && (ModifierKeys & Keys.Control) == Keys.Control)
+ {
+ VScroll = false;
+ HScroll = false;
+ base.OnMouseWheel(e);
+ VScroll = true;
+ HScroll = true;
+ }
+ else
+ {
+ //Vertical Scoll with SHIFT key pressed
+ if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift)
+ {
+ VScroll = false;
+ base.OnMouseWheel(e);
+ VScroll = true;
+ }
+ else
+ {
+ base.OnMouseWheel(e);
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/Pipette.cs b/src/Greenshot.Editor/Controls/Pipette.cs
similarity index 95%
rename from src/Greenshot/Controls/Pipette.cs
rename to src/Greenshot.Editor/Controls/Pipette.cs
index f14d02150..d31017b92 100644
--- a/src/Greenshot/Controls/Pipette.cs
+++ b/src/Greenshot.Editor/Controls/Pipette.cs
@@ -1,204 +1,204 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using System.Windows.Forms;
-using Greenshot.Base.UnmanagedHelpers;
-using Greenshot.Base.UnmanagedHelpers.Enums;
-using Greenshot.Forms;
-using ColorDialog = Greenshot.Forms.ColorDialog;
-
-namespace Greenshot.Controls
-{
- ///
- /// This code was supplied by Hi-Coder as a patch for Greenshot
- /// Needed some modifications to be stable.
- ///
- public sealed class Pipette : Label, IMessageFilter, IDisposable
- {
- private MovableShowColorForm _movableShowColorForm;
- private bool _dragging;
- private Cursor _cursor;
- private readonly Bitmap _image;
- private const int VkEsc = 27;
-
- public event EventHandler PipetteUsed;
-
- public Pipette()
- {
- BorderStyle = BorderStyle.FixedSingle;
- _dragging = false;
- _image = (Bitmap) new ComponentResourceManager(typeof(ColorDialog)).GetObject("pipette.Image");
- Image = _image;
- _cursor = CreateCursor(_image, 1, 14);
- _movableShowColorForm = new MovableShowColorForm();
- Application.AddMessageFilter(this);
- }
-
- ///
- /// Create a cursor from the supplied bitmap & hotspot coordinates
- ///
- /// Bitmap to create an icon from
- /// Hotspot X coordinate
- /// Hotspot Y coordinate
- /// Cursor
- private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY)
- {
- using SafeIconHandle iconHandle = new SafeIconHandle(bitmap.GetHicon());
- User32.GetIconInfo(iconHandle, out var iconInfo);
- iconInfo.xHotspot = hotspotX;
- iconInfo.yHotspot = hotspotY;
- iconInfo.fIcon = false;
- var icon = User32.CreateIconIndirect(ref iconInfo);
- return new Cursor(icon);
- }
-
- ///
- /// The bulk of the clean-up code is implemented in Dispose(bool)
- ///
- public new void Dispose()
- {
- Dispose(true);
- }
-
- ///
- /// This Dispose is called from the Dispose and the Destructor.
- ///
- /// When disposing==true all non-managed resources should be freed too!
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (_cursor != null)
- {
- _cursor.Dispose();
- }
-
- _movableShowColorForm?.Dispose();
- }
-
- _movableShowColorForm = null;
- _cursor = null;
- base.Dispose(disposing);
- }
-
- ///
- /// Handle the mouse down on the Pipette "label", we take the capture and move the zoomer to the current location
- ///
- /// MouseEventArgs
- protected override void OnMouseDown(MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Left)
- {
- User32.SetCapture(Handle);
- _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y)));
- }
-
- base.OnMouseDown(e);
- }
-
- ///
- /// Handle the mouse up on the Pipette "label", we release the capture and fire the PipetteUsed event
- ///
- /// MouseEventArgs
- protected override void OnMouseUp(MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Left)
- {
- //Release Capture should consume MouseUp when canceled with the escape key
- User32.ReleaseCapture();
- PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color));
- }
-
- base.OnMouseUp(e);
- }
-
- ///
- /// Handle the mouse Move event, we move the ColorUnderCursor to the current location.
- ///
- /// MouseEventArgs
- protected override void OnMouseMove(MouseEventArgs e)
- {
- if (_dragging)
- {
- //display the form on the right side of the cursor by default;
- Point zp = PointToScreen(new Point(e.X, e.Y));
- _movableShowColorForm.MoveTo(zp);
- }
-
- base.OnMouseMove(e);
- }
-
- ///
- /// Handle the MouseCaptureChanged event
- ///
- ///
- protected override void OnMouseCaptureChanged(EventArgs e)
- {
- if (Capture)
- {
- _dragging = true;
- Image = null;
- Cursor c = _cursor;
- Cursor = c;
- _movableShowColorForm.Visible = true;
- }
- else
- {
- _dragging = false;
- Image = _image;
- Cursor = Cursors.Arrow;
- _movableShowColorForm.Visible = false;
- }
-
- Update();
- base.OnMouseCaptureChanged(e);
- }
-
- public bool PreFilterMessage(ref Message m)
- {
- if (_dragging)
- {
- if (m.Msg == (int) WindowsMessages.WM_CHAR)
- {
- if ((int) m.WParam == VkEsc)
- {
- User32.ReleaseCapture();
- }
- }
- }
-
- return false;
- }
- }
-
- public class PipetteUsedArgs : EventArgs
- {
- public Color Color;
-
- public PipetteUsedArgs(Color c)
- {
- Color = c;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+using Greenshot.Base.UnmanagedHelpers;
+using Greenshot.Base.UnmanagedHelpers.Enums;
+using Greenshot.Editor.Forms;
+using ColorDialog = Greenshot.Editor.Forms.ColorDialog;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// This code was supplied by Hi-Coder as a patch for Greenshot
+ /// Needed some modifications to be stable.
+ ///
+ public sealed class Pipette : Label, IMessageFilter, IDisposable
+ {
+ private MovableShowColorForm _movableShowColorForm;
+ private bool _dragging;
+ private Cursor _cursor;
+ private readonly Bitmap _image;
+ private const int VkEsc = 27;
+
+ public event EventHandler PipetteUsed;
+
+ public Pipette()
+ {
+ BorderStyle = BorderStyle.FixedSingle;
+ _dragging = false;
+ _image = (Bitmap) new ComponentResourceManager(typeof(ColorDialog)).GetObject("pipette.Image");
+ Image = _image;
+ _cursor = CreateCursor(_image, 1, 14);
+ _movableShowColorForm = new MovableShowColorForm();
+ Application.AddMessageFilter(this);
+ }
+
+ ///
+ /// Create a cursor from the supplied bitmap & hotspot coordinates
+ ///
+ /// Bitmap to create an icon from
+ /// Hotspot X coordinate
+ /// Hotspot Y coordinate
+ /// Cursor
+ private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY)
+ {
+ using SafeIconHandle iconHandle = new SafeIconHandle(bitmap.GetHicon());
+ User32.GetIconInfo(iconHandle, out var iconInfo);
+ iconInfo.xHotspot = hotspotX;
+ iconInfo.yHotspot = hotspotY;
+ iconInfo.fIcon = false;
+ var icon = User32.CreateIconIndirect(ref iconInfo);
+ return new Cursor(icon);
+ }
+
+ ///
+ /// The bulk of the clean-up code is implemented in Dispose(bool)
+ ///
+ public new void Dispose()
+ {
+ Dispose(true);
+ }
+
+ ///
+ /// This Dispose is called from the Dispose and the Destructor.
+ ///
+ /// When disposing==true all non-managed resources should be freed too!
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_cursor != null)
+ {
+ _cursor.Dispose();
+ }
+
+ _movableShowColorForm?.Dispose();
+ }
+
+ _movableShowColorForm = null;
+ _cursor = null;
+ base.Dispose(disposing);
+ }
+
+ ///
+ /// Handle the mouse down on the Pipette "label", we take the capture and move the zoomer to the current location
+ ///
+ /// MouseEventArgs
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ if (e.Button == MouseButtons.Left)
+ {
+ User32.SetCapture(Handle);
+ _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y)));
+ }
+
+ base.OnMouseDown(e);
+ }
+
+ ///
+ /// Handle the mouse up on the Pipette "label", we release the capture and fire the PipetteUsed event
+ ///
+ /// MouseEventArgs
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ if (e.Button == MouseButtons.Left)
+ {
+ //Release Capture should consume MouseUp when canceled with the escape key
+ User32.ReleaseCapture();
+ PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color));
+ }
+
+ base.OnMouseUp(e);
+ }
+
+ ///
+ /// Handle the mouse Move event, we move the ColorUnderCursor to the current location.
+ ///
+ /// MouseEventArgs
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ if (_dragging)
+ {
+ //display the form on the right side of the cursor by default;
+ Point zp = PointToScreen(new Point(e.X, e.Y));
+ _movableShowColorForm.MoveTo(zp);
+ }
+
+ base.OnMouseMove(e);
+ }
+
+ ///
+ /// Handle the MouseCaptureChanged event
+ ///
+ ///
+ protected override void OnMouseCaptureChanged(EventArgs e)
+ {
+ if (Capture)
+ {
+ _dragging = true;
+ Image = null;
+ Cursor c = _cursor;
+ Cursor = c;
+ _movableShowColorForm.Visible = true;
+ }
+ else
+ {
+ _dragging = false;
+ Image = _image;
+ Cursor = Cursors.Arrow;
+ _movableShowColorForm.Visible = false;
+ }
+
+ Update();
+ base.OnMouseCaptureChanged(e);
+ }
+
+ public bool PreFilterMessage(ref Message m)
+ {
+ if (_dragging)
+ {
+ if (m.Msg == (int) WindowsMessages.WM_CHAR)
+ {
+ if ((int) m.WParam == VkEsc)
+ {
+ User32.ReleaseCapture();
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+
+ public class PipetteUsedArgs : EventArgs
+ {
+ public Color Color;
+
+ public PipetteUsedArgs(Color c)
+ {
+ Color = c;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/ToolStripColorButton.cs b/src/Greenshot.Editor/Controls/ToolStripColorButton.cs
similarity index 94%
rename from src/Greenshot/Controls/ToolStripColorButton.cs
rename to src/Greenshot.Editor/Controls/ToolStripColorButton.cs
index 86bfd7241..91386b4f4 100644
--- a/src/Greenshot/Controls/ToolStripColorButton.cs
+++ b/src/Greenshot.Editor/Controls/ToolStripColorButton.cs
@@ -1,97 +1,97 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Windows.Forms;
-using Greenshot.Base.Controls;
-using ColorDialog = Greenshot.Forms.ColorDialog;
-
-namespace Greenshot.Controls
-{
- public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
- public string LanguageKey { get; set; }
-
- private Color _selectedColor = Color.Transparent;
-
- public ToolStripColorButton()
- {
- Click += ColorButtonClick;
- }
-
- public Color SelectedColor
- {
- get { return _selectedColor; }
- set
- {
- _selectedColor = value;
-
- Brush brush;
- if (value != Color.Transparent)
- {
- brush = new SolidBrush(value);
- }
- else
- {
- brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray);
- }
-
- if (Image != null)
- {
- using Graphics graphics = Graphics.FromImage(Image);
- graphics.FillRectangle(brush, new Rectangle(0, 13, 16, 3));
- }
-
- // cleanup GDI Object
- brush.Dispose();
- Invalidate();
- }
- }
-
- private void ColorButtonClick(object sender, EventArgs e)
- {
- var colorDialog = new ColorDialog
- {
- Color = SelectedColor
- };
- // Using the parent to make sure the dialog doesn't show on another window
- colorDialog.ShowDialog(Parent.Parent);
- if (colorDialog.DialogResult == DialogResult.Cancel)
- {
- return;
- }
-
- if (colorDialog.Color.Equals(SelectedColor))
- {
- return;
- }
-
- SelectedColor = colorDialog.Color;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor"));
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using Greenshot.Base.Controls;
+using ColorDialog = Greenshot.Editor.Forms.ColorDialog;
+
+namespace Greenshot.Editor.Controls
+{
+ public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")]
+ public string LanguageKey { get; set; }
+
+ private Color _selectedColor = Color.Transparent;
+
+ public ToolStripColorButton()
+ {
+ Click += ColorButtonClick;
+ }
+
+ public Color SelectedColor
+ {
+ get { return _selectedColor; }
+ set
+ {
+ _selectedColor = value;
+
+ Brush brush;
+ if (value != Color.Transparent)
+ {
+ brush = new SolidBrush(value);
+ }
+ else
+ {
+ brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray);
+ }
+
+ if (Image != null)
+ {
+ using Graphics graphics = Graphics.FromImage(Image);
+ graphics.FillRectangle(brush, new Rectangle(0, 13, 16, 3));
+ }
+
+ // cleanup GDI Object
+ brush.Dispose();
+ Invalidate();
+ }
+ }
+
+ private void ColorButtonClick(object sender, EventArgs e)
+ {
+ var colorDialog = new ColorDialog
+ {
+ Color = SelectedColor
+ };
+ // Using the parent to make sure the dialog doesn't show on another window
+ colorDialog.ShowDialog(Parent.Parent);
+ if (colorDialog.DialogResult == DialogResult.Cancel)
+ {
+ return;
+ }
+
+ if (colorDialog.Color.Equals(SelectedColor))
+ {
+ return;
+ }
+
+ SelectedColor = colorDialog.Color;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/ToolStripEx.cs b/src/Greenshot.Editor/Controls/ToolStripEx.cs
similarity index 95%
rename from src/Greenshot/Controls/ToolStripEx.cs
rename to src/Greenshot.Editor/Controls/ToolStripEx.cs
index 216873481..39e1859cc 100644
--- a/src/Greenshot/Controls/ToolStripEx.cs
+++ b/src/Greenshot.Editor/Controls/ToolStripEx.cs
@@ -1,66 +1,66 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Windows.Forms;
-
-namespace Greenshot.Controls
-{
- ///
- /// This is an extension of the default ToolStrip and allows us to click it even when the form doesn't have focus.
- /// See: https://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx
- ///
- internal class ToolStripEx : ToolStrip
- {
- private const int WM_MOUSEACTIVATE = 0x21;
-
- private enum NativeConstants : uint
- {
- MA_ACTIVATE = 1,
- MA_ACTIVATEANDEAT = 2,
- }
-
- private bool _clickThrough;
-
- ///
- /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus.
- ///
- ///
- /// Default value is false, which is the same behavior provided by the base ToolStrip class.
- ///
-
- public bool ClickThrough
- {
- get { return _clickThrough; }
-
- set { _clickThrough = value; }
- }
-
- protected override void WndProc(ref Message m)
- {
- base.WndProc(ref m);
- if (_clickThrough && m.Msg == WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT)
- {
- m.Result = (IntPtr) NativeConstants.MA_ACTIVATE;
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Windows.Forms;
+
+namespace Greenshot.Editor.Controls
+{
+ ///
+ /// This is an extension of the default ToolStrip and allows us to click it even when the form doesn't have focus.
+ /// See: https://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx
+ ///
+ internal class ToolStripEx : ToolStrip
+ {
+ private const int WM_MOUSEACTIVATE = 0x21;
+
+ private enum NativeConstants : uint
+ {
+ MA_ACTIVATE = 1,
+ MA_ACTIVATEANDEAT = 2,
+ }
+
+ private bool _clickThrough;
+
+ ///
+ /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus.
+ ///
+ ///
+ /// Default value is false, which is the same behavior provided by the base ToolStrip class.
+ ///
+
+ public bool ClickThrough
+ {
+ get { return _clickThrough; }
+
+ set { _clickThrough = value; }
+ }
+
+ protected override void WndProc(ref Message m)
+ {
+ base.WndProc(ref m);
+ if (_clickThrough && m.Msg == WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT)
+ {
+ m.Result = (IntPtr) NativeConstants.MA_ACTIVATE;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Controls/ToolStripNumericUpDown.cs b/src/Greenshot.Editor/Controls/ToolStripNumericUpDown.cs
similarity index 96%
rename from src/Greenshot/Controls/ToolStripNumericUpDown.cs
rename to src/Greenshot.Editor/Controls/ToolStripNumericUpDown.cs
index a27266152..89caa257c 100644
--- a/src/Greenshot/Controls/ToolStripNumericUpDown.cs
+++ b/src/Greenshot.Editor/Controls/ToolStripNumericUpDown.cs
@@ -1,88 +1,88 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Windows.Forms;
-using System.Windows.Forms.Design;
-
-namespace Greenshot.Controls
-{
- [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)]
- public class ToolStripNumericUpDown : ToolStripControlHost, INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- public ToolStripNumericUpDown() : base(new NumericUpDown())
- {
- }
-
- public NumericUpDown NumericUpDown => Control as NumericUpDown;
-
- public decimal Value
- {
- get { return NumericUpDown.Value; }
- set { NumericUpDown.Value = value; }
- }
-
- public decimal Minimum
- {
- get { return NumericUpDown.Minimum; }
- set { NumericUpDown.Minimum = value; }
- }
-
- public decimal Maximum
- {
- get { return NumericUpDown.Maximum; }
- set { NumericUpDown.Maximum = value; }
- }
-
- public decimal Increment
- {
- get { return NumericUpDown.Increment; }
- set { NumericUpDown.Increment = value; }
- }
-
- public int DecimalPlaces
- {
- get { return NumericUpDown.DecimalPlaces; }
- set { NumericUpDown.DecimalPlaces = value; }
- }
-
-
- protected override void OnSubscribeControlEvents(Control control)
- {
- base.OnSubscribeControlEvents(control);
- NumericUpDown.ValueChanged += _valueChanged;
- }
-
- protected override void OnUnsubscribeControlEvents(Control control)
- {
- base.OnUnsubscribeControlEvents(control);
- NumericUpDown.ValueChanged -= _valueChanged;
- }
-
- private void _valueChanged(object sender, EventArgs e)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Windows.Forms.Design;
+
+namespace Greenshot.Editor.Controls
+{
+ [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)]
+ public class ToolStripNumericUpDown : ToolStripControlHost, INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public ToolStripNumericUpDown() : base(new NumericUpDown())
+ {
+ }
+
+ public NumericUpDown NumericUpDown => Control as NumericUpDown;
+
+ public decimal Value
+ {
+ get { return NumericUpDown.Value; }
+ set { NumericUpDown.Value = value; }
+ }
+
+ public decimal Minimum
+ {
+ get { return NumericUpDown.Minimum; }
+ set { NumericUpDown.Minimum = value; }
+ }
+
+ public decimal Maximum
+ {
+ get { return NumericUpDown.Maximum; }
+ set { NumericUpDown.Maximum = value; }
+ }
+
+ public decimal Increment
+ {
+ get { return NumericUpDown.Increment; }
+ set { NumericUpDown.Increment = value; }
+ }
+
+ public int DecimalPlaces
+ {
+ get { return NumericUpDown.DecimalPlaces; }
+ set { NumericUpDown.DecimalPlaces = value; }
+ }
+
+
+ protected override void OnSubscribeControlEvents(Control control)
+ {
+ base.OnSubscribeControlEvents(control);
+ NumericUpDown.ValueChanged += _valueChanged;
+ }
+
+ protected override void OnUnsubscribeControlEvents(Control control)
+ {
+ base.OnUnsubscribeControlEvents(control);
+ NumericUpDown.ValueChanged -= _valueChanged;
+ }
+
+ private void _valueChanged(object sender, EventArgs e)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Destinations/EditorDestination.cs b/src/Greenshot.Editor/Destinations/EditorDestination.cs
similarity index 95%
rename from src/Greenshot/Destinations/EditorDestination.cs
rename to src/Greenshot.Editor/Destinations/EditorDestination.cs
index f7cf6d2e8..326397ec9 100644
--- a/src/Greenshot/Destinations/EditorDestination.cs
+++ b/src/Greenshot.Editor/Destinations/EditorDestination.cs
@@ -1,154 +1,154 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using Greenshot.Base.Core;
-using Greenshot.Base.IniFile;
-using Greenshot.Base.Interfaces;
-using Greenshot.Base.Interfaces.Forms;
-using Greenshot.Configuration;
-using Greenshot.Forms;
-using log4net;
-
-namespace Greenshot.Destinations
-{
- ///
- /// Description of EditorDestination.
- ///
- public class EditorDestination : AbstractDestination
- {
- private static readonly ILog LOG = LogManager.GetLogger(typeof(EditorDestination));
- private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection();
- public const string DESIGNATION = "Editor";
- private readonly IImageEditor editor;
- private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap();
-
- public EditorDestination()
- {
- // Do not remove, is needed for the framework
- }
-
- public EditorDestination(IImageEditor editor)
- {
- this.editor = editor;
- }
-
- public override string Designation => DESIGNATION;
-
- public override string Description
- {
- get
- {
- if (editor == null)
- {
- return Language.GetString(LangKey.settings_destination_editor);
- }
-
- return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title;
- }
- }
-
- public override int Priority => 1;
-
- public override bool IsDynamic => true;
-
- public override Image DisplayIcon => greenshotIcon;
-
- public override IEnumerable DynamicDestinations()
- {
- foreach (IImageEditor someEditor in ImageEditorForm.Editors)
- {
- yield return new EditorDestination(someEditor);
- }
- }
-
- public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
- {
- ExportInformation exportInformation = new ExportInformation(Designation, Description);
- // Make sure we collect the garbage before opening the screenshot
- GC.Collect();
- GC.WaitForPendingFinalizers();
-
- bool modified = surface.Modified;
- if (editor == null)
- {
- if (editorConfiguration.ReuseEditor)
- {
- foreach (IImageEditor openedEditor in ImageEditorForm.Editors)
- {
- if (openedEditor.Surface.Modified) continue;
-
- openedEditor.Surface = surface;
- exportInformation.ExportMade = true;
- break;
- }
- }
-
- if (!exportInformation.ExportMade)
- {
- try
- {
- ImageEditorForm editorForm = new ImageEditorForm(surface, !surface.Modified); // Output made??
-
- if (!string.IsNullOrEmpty(captureDetails.Filename))
- {
- editorForm.SetImagePath(captureDetails.Filename);
- }
-
- editorForm.Show();
- editorForm.Activate();
- LOG.Debug("Finished opening Editor");
- exportInformation.ExportMade = true;
- }
- catch (Exception e)
- {
- LOG.Error(e);
- exportInformation.ErrorMessage = e.Message;
- }
- }
- }
- else
- {
- try
- {
- using (Image image = surface.GetImageForExport())
- {
- editor.Surface.AddImageContainer(image, 10, 10);
- }
-
- exportInformation.ExportMade = true;
- }
- catch (Exception e)
- {
- LOG.Error(e);
- exportInformation.ErrorMessage = e.Message;
- }
- }
-
- ProcessExport(exportInformation, surface);
- // Workaround for the modified flag when using the editor.
- surface.Modified = modified;
- return exportInformation;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using Greenshot.Base.Core;
+using Greenshot.Base.IniFile;
+using Greenshot.Base.Interfaces;
+using Greenshot.Base.Interfaces.Forms;
+using Greenshot.Editor.Configuration;
+using Greenshot.Editor.Forms;
+using log4net;
+
+namespace Greenshot.Editor.Destinations
+{
+ ///
+ /// Description of EditorDestination.
+ ///
+ public class EditorDestination : AbstractDestination
+ {
+ private static readonly ILog LOG = LogManager.GetLogger(typeof(EditorDestination));
+ private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection();
+ public const string DESIGNATION = "Editor";
+ private readonly IImageEditor editor;
+ private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap();
+
+ public EditorDestination()
+ {
+ // Do not remove, is needed for the framework
+ }
+
+ public EditorDestination(IImageEditor editor)
+ {
+ this.editor = editor;
+ }
+
+ public override string Designation => DESIGNATION;
+
+ public override string Description
+ {
+ get
+ {
+ if (editor == null)
+ {
+ return Language.GetString(LangKey.settings_destination_editor);
+ }
+
+ return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title;
+ }
+ }
+
+ public override int Priority => 1;
+
+ public override bool IsDynamic => true;
+
+ public override Image DisplayIcon => greenshotIcon;
+
+ public override IEnumerable DynamicDestinations()
+ {
+ foreach (IImageEditor someEditor in ImageEditorForm.Editors)
+ {
+ yield return new EditorDestination(someEditor);
+ }
+ }
+
+ public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
+ {
+ ExportInformation exportInformation = new ExportInformation(Designation, Description);
+ // Make sure we collect the garbage before opening the screenshot
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+
+ bool modified = surface.Modified;
+ if (editor == null)
+ {
+ if (editorConfiguration.ReuseEditor)
+ {
+ foreach (IImageEditor openedEditor in ImageEditorForm.Editors)
+ {
+ if (openedEditor.Surface.Modified) continue;
+
+ openedEditor.Surface = surface;
+ exportInformation.ExportMade = true;
+ break;
+ }
+ }
+
+ if (!exportInformation.ExportMade)
+ {
+ try
+ {
+ ImageEditorForm editorForm = new ImageEditorForm(surface, !surface.Modified); // Output made??
+
+ if (!string.IsNullOrEmpty(captureDetails.Filename))
+ {
+ editorForm.SetImagePath(captureDetails.Filename);
+ }
+
+ editorForm.Show();
+ editorForm.Activate();
+ LOG.Debug("Finished opening Editor");
+ exportInformation.ExportMade = true;
+ }
+ catch (Exception e)
+ {
+ LOG.Error(e);
+ exportInformation.ErrorMessage = e.Message;
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ using (Image image = surface.GetImageForExport())
+ {
+ editor.Surface.AddImageContainer(image, 10, 10);
+ }
+
+ exportInformation.ExportMade = true;
+ }
+ catch (Exception e)
+ {
+ LOG.Error(e);
+ exportInformation.ErrorMessage = e.Message;
+ }
+ }
+
+ ProcessExport(exportInformation, surface);
+ // Workaround for the modified flag when using the editor.
+ surface.Modified = modified;
+ return exportInformation;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs
similarity index 96%
rename from src/Greenshot/Drawing/Adorners/AbstractAdorner.cs
rename to src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs
index a8bd3cd47..028306e24 100644
--- a/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs
+++ b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs
@@ -1,156 +1,156 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Windows.Forms;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Base.Interfaces.Drawing.Adorners;
-
-namespace Greenshot.Drawing.Adorners
-{
- public class AbstractAdorner : IAdorner
- {
- public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE;
-
- private static readonly Size DefaultSize = new Size(6, 6);
- protected Size _size;
-
- public AbstractAdorner(IDrawableContainer owner)
- {
- _size = DpiHelper.ScaleWithDpi(DefaultSize, 0);
- Owner = owner;
- }
-
- ///
- /// Returns the cursor for when the mouse is over the adorner
- ///
- public virtual Cursor Cursor
- {
- get { return Cursors.SizeAll; }
- }
-
- public virtual IDrawableContainer Owner { get; set; }
-
- ///
- /// Test if the point is inside the adorner
- ///
- ///
- ///
- public virtual bool HitTest(Point point)
- {
- Rectangle hitBounds = Bounds;
- hitBounds.Inflate(3, 3);
- return hitBounds.Contains(point);
- }
-
- ///
- /// Handle the mouse down
- ///
- ///
- ///
- public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs)
- {
- }
-
- ///
- /// Handle the mouse move
- ///
- ///
- ///
- public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs)
- {
- }
-
- ///
- /// Handle the mouse up
- ///
- ///
- ///
- public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs)
- {
- EditStatus = EditStatus.IDLE;
- }
-
- ///
- /// Return the location of the adorner
- ///
- public virtual Point Location { get; set; }
-
- ///
- /// Return the bounds of the Adorner
- ///
- public virtual Rectangle Bounds
- {
- get
- {
- Point location = Location;
- return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height);
- }
- }
-
- ///
- /// Return the bounds of the Adorner as displayed on the parent Surface
- ///
- 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);
- }
- }
-
- ///
- /// The adorner is active if the edit status is not idle or undrawn
- ///
- public virtual bool IsActive
- {
- get { return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; }
- }
-
- ///
- /// Adjust UI elements to the supplied DPI settings
- ///
- /// uint
- public void AdjustToDpi(uint dpi)
- {
- _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi);
- }
-
- ///
- /// Draw the adorner
- ///
- /// PaintEventArgs
- public virtual void Paint(PaintEventArgs paintEventArgs)
- {
- }
-
- ///
- /// We ignore the Transform, as the coordinates are directly bound to those of the owner
- ///
- ///
- public virtual void Transform(Matrix matrix)
- {
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Base.Interfaces.Drawing.Adorners;
+
+namespace Greenshot.Editor.Drawing.Adorners
+{
+ public class AbstractAdorner : IAdorner
+ {
+ public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE;
+
+ private static readonly Size DefaultSize = new Size(6, 6);
+ protected Size _size;
+
+ public AbstractAdorner(IDrawableContainer owner)
+ {
+ _size = DpiHelper.ScaleWithDpi(DefaultSize, 0);
+ Owner = owner;
+ }
+
+ ///
+ /// Returns the cursor for when the mouse is over the adorner
+ ///
+ public virtual Cursor Cursor
+ {
+ get { return Cursors.SizeAll; }
+ }
+
+ public virtual IDrawableContainer Owner { get; set; }
+
+ ///
+ /// Test if the point is inside the adorner
+ ///
+ ///
+ ///
+ public virtual bool HitTest(Point point)
+ {
+ Rectangle hitBounds = Bounds;
+ hitBounds.Inflate(3, 3);
+ return hitBounds.Contains(point);
+ }
+
+ ///
+ /// Handle the mouse down
+ ///
+ ///
+ ///
+ public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs)
+ {
+ }
+
+ ///
+ /// Handle the mouse move
+ ///
+ ///
+ ///
+ public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs)
+ {
+ }
+
+ ///
+ /// Handle the mouse up
+ ///
+ ///
+ ///
+ public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs)
+ {
+ EditStatus = EditStatus.IDLE;
+ }
+
+ ///
+ /// Return the location of the adorner
+ ///
+ public virtual Point Location { get; set; }
+
+ ///
+ /// Return the bounds of the Adorner
+ ///
+ public virtual Rectangle Bounds
+ {
+ get
+ {
+ Point location = Location;
+ return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height);
+ }
+ }
+
+ ///
+ /// Return the bounds of the Adorner as displayed on the parent Surface
+ ///
+ 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);
+ }
+ }
+
+ ///
+ /// The adorner is active if the edit status is not idle or undrawn
+ ///
+ public virtual bool IsActive
+ {
+ get { return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; }
+ }
+
+ ///
+ /// Adjust UI elements to the supplied DPI settings
+ ///
+ /// uint
+ public void AdjustToDpi(uint dpi)
+ {
+ _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi);
+ }
+
+ ///
+ /// Draw the adorner
+ ///
+ /// PaintEventArgs
+ public virtual void Paint(PaintEventArgs paintEventArgs)
+ {
+ }
+
+ ///
+ /// We ignore the Transform, as the coordinates are directly bound to those of the owner
+ ///
+ ///
+ public virtual void Transform(Matrix matrix)
+ {
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs
similarity index 96%
rename from src/Greenshot/Drawing/Adorners/MoveAdorner.cs
rename to src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs
index 9ba4d1f46..ad1355ced 100644
--- a/src/Greenshot/Drawing/Adorners/MoveAdorner.cs
+++ b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs
@@ -1,166 +1,166 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Helpers;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Windows.Forms;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Adorners
-{
- ///
- /// This is the adorner for the line based containers
- ///
- public class MoveAdorner : AbstractAdorner
- {
- private Rectangle _boundsBeforeResize = Rectangle.Empty;
- private RectangleF _boundsAfterResize = RectangleF.Empty;
-
- public Positions Position { get; private set; }
-
- public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner)
- {
- Position = position;
- }
-
- ///
- /// Returns the cursor for when the mouse is over the adorner
- ///
- public override Cursor Cursor => Cursors.SizeAll;
-
- ///
- /// Handle the mouse down
- ///
- ///
- ///
- public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
- {
- EditStatus = EditStatus.RESIZING;
- _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height);
- _boundsAfterResize = _boundsBeforeResize;
- }
-
- ///
- /// Handle the mouse move
- ///
- ///
- ///
- public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
- {
- if (EditStatus != EditStatus.RESIZING)
- {
- return;
- }
-
- Owner.Invalidate();
- Owner.MakeBoundsChangeUndoable(false);
-
- // reset "workbench" rectangle to current bounds
- _boundsAfterResize.X = _boundsBeforeResize.X;
- _boundsAfterResize.Y = _boundsBeforeResize.Y;
- _boundsAfterResize.Width = _boundsBeforeResize.Width;
- _boundsAfterResize.Height = _boundsBeforeResize.Height;
-
- // calculate scaled rectangle
- ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions());
-
- // apply scaled bounds to this DrawableContainer
- Owner.ApplyBounds(_boundsAfterResize);
-
- Owner.Invalidate();
- }
-
- ///
- /// Return the location of the adorner
- ///
- public override Point Location
- {
- get
- {
- int x = 0, y = 0;
- switch (Position)
- {
- case Positions.TopLeft:
- x = Owner.Left;
- y = Owner.Top;
- break;
- case Positions.BottomLeft:
- x = Owner.Left;
- y = Owner.Top + Owner.Height;
- break;
- case Positions.MiddleLeft:
- x = Owner.Left;
- y = Owner.Top + (Owner.Height / 2);
- break;
- case Positions.TopCenter:
- x = Owner.Left + (Owner.Width / 2);
- y = Owner.Top;
- break;
- case Positions.BottomCenter:
- x = Owner.Left + (Owner.Width / 2);
- y = Owner.Top + Owner.Height;
- break;
- case Positions.TopRight:
- x = Owner.Left + Owner.Width;
- y = Owner.Top;
- break;
- case Positions.BottomRight:
- x = Owner.Left + Owner.Width;
- y = Owner.Top + Owner.Height;
- break;
- case Positions.MiddleRight:
- x = Owner.Left + Owner.Width;
- y = Owner.Top + (Owner.Height / 2);
- break;
- }
-
- return new Point(x, y);
- }
- }
-
- ///
- /// Draw the adorner
- ///
- /// PaintEventArgs
- public override void Paint(PaintEventArgs paintEventArgs)
- {
- Graphics targetGraphics = paintEventArgs.Graphics;
-
- var bounds = BoundsOnSurface;
- GraphicsState state = targetGraphics.Save();
-
- targetGraphics.CompositingMode = CompositingMode.SourceCopy;
-
- try
- {
- targetGraphics.FillRectangle(Brushes.Black, bounds);
- targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds);
- }
- catch
- {
- // Ignore, BUG-2065
- }
-
- targetGraphics.Restore(state);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing.Adorners
+{
+ ///
+ /// This is the adorner for the line based containers
+ ///
+ public class MoveAdorner : AbstractAdorner
+ {
+ private Rectangle _boundsBeforeResize = Rectangle.Empty;
+ private RectangleF _boundsAfterResize = RectangleF.Empty;
+
+ public Positions Position { get; private set; }
+
+ public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner)
+ {
+ Position = position;
+ }
+
+ ///
+ /// Returns the cursor for when the mouse is over the adorner
+ ///
+ public override Cursor Cursor => Cursors.SizeAll;
+
+ ///
+ /// Handle the mouse down
+ ///
+ ///
+ ///
+ public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
+ {
+ EditStatus = EditStatus.RESIZING;
+ _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height);
+ _boundsAfterResize = _boundsBeforeResize;
+ }
+
+ ///
+ /// Handle the mouse move
+ ///
+ ///
+ ///
+ public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
+ {
+ if (EditStatus != EditStatus.RESIZING)
+ {
+ return;
+ }
+
+ Owner.Invalidate();
+ Owner.MakeBoundsChangeUndoable(false);
+
+ // reset "workbench" rectangle to current bounds
+ _boundsAfterResize.X = _boundsBeforeResize.X;
+ _boundsAfterResize.Y = _boundsBeforeResize.Y;
+ _boundsAfterResize.Width = _boundsBeforeResize.Width;
+ _boundsAfterResize.Height = _boundsBeforeResize.Height;
+
+ // calculate scaled rectangle
+ ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions());
+
+ // apply scaled bounds to this DrawableContainer
+ Owner.ApplyBounds(_boundsAfterResize);
+
+ Owner.Invalidate();
+ }
+
+ ///
+ /// Return the location of the adorner
+ ///
+ public override Point Location
+ {
+ get
+ {
+ int x = 0, y = 0;
+ switch (Position)
+ {
+ case Positions.TopLeft:
+ x = Owner.Left;
+ y = Owner.Top;
+ break;
+ case Positions.BottomLeft:
+ x = Owner.Left;
+ y = Owner.Top + Owner.Height;
+ break;
+ case Positions.MiddleLeft:
+ x = Owner.Left;
+ y = Owner.Top + (Owner.Height / 2);
+ break;
+ case Positions.TopCenter:
+ x = Owner.Left + (Owner.Width / 2);
+ y = Owner.Top;
+ break;
+ case Positions.BottomCenter:
+ x = Owner.Left + (Owner.Width / 2);
+ y = Owner.Top + Owner.Height;
+ break;
+ case Positions.TopRight:
+ x = Owner.Left + Owner.Width;
+ y = Owner.Top;
+ break;
+ case Positions.BottomRight:
+ x = Owner.Left + Owner.Width;
+ y = Owner.Top + Owner.Height;
+ break;
+ case Positions.MiddleRight:
+ x = Owner.Left + Owner.Width;
+ y = Owner.Top + (Owner.Height / 2);
+ break;
+ }
+
+ return new Point(x, y);
+ }
+ }
+
+ ///
+ /// Draw the adorner
+ ///
+ /// PaintEventArgs
+ public override void Paint(PaintEventArgs paintEventArgs)
+ {
+ Graphics targetGraphics = paintEventArgs.Graphics;
+
+ var bounds = BoundsOnSurface;
+ GraphicsState state = targetGraphics.Save();
+
+ targetGraphics.CompositingMode = CompositingMode.SourceCopy;
+
+ try
+ {
+ targetGraphics.FillRectangle(Brushes.Black, bounds);
+ targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds);
+ }
+ catch
+ {
+ // Ignore, BUG-2065
+ }
+
+ targetGraphics.Restore(state);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs
similarity index 96%
rename from src/Greenshot/Drawing/Adorners/ResizeAdorner.cs
rename to src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs
index 21757a66a..052abaaa4 100644
--- a/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs
+++ b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs
@@ -1,186 +1,186 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Helpers;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Windows.Forms;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Adorners
-{
- ///
- /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble
- ///
- public class ResizeAdorner : AbstractAdorner
- {
- private Rectangle _boundsBeforeResize = Rectangle.Empty;
- private RectangleF _boundsAfterResize = RectangleF.Empty;
-
- public Positions Position { get; private set; }
-
- public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner)
- {
- Position = position;
- }
-
- ///
- /// Returns the cursor for when the mouse is over the adorner
- ///
- public override Cursor Cursor
- {
- get
- {
- bool isNotSwitched = Owner.Width >= 0;
- if (Owner.Height < 0)
- {
- isNotSwitched = !isNotSwitched;
- }
-
- switch (Position)
- {
- case Positions.TopLeft:
- case Positions.BottomRight:
- return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW;
- case Positions.TopRight:
- case Positions.BottomLeft:
- return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE;
- case Positions.MiddleLeft:
- case Positions.MiddleRight:
- return Cursors.SizeWE;
- case Positions.TopCenter:
- case Positions.BottomCenter:
- return Cursors.SizeNS;
- default:
- return Cursors.SizeAll;
- }
- }
- }
-
- ///
- /// Handle the mouse down
- ///
- ///
- ///
- public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
- {
- EditStatus = EditStatus.RESIZING;
- _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height);
- _boundsAfterResize = _boundsBeforeResize;
- }
-
- ///
- /// Handle the mouse move
- ///
- ///
- ///
- public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
- {
- if (EditStatus != EditStatus.RESIZING)
- {
- return;
- }
-
- Owner.Invalidate();
- Owner.MakeBoundsChangeUndoable(false);
-
- // reset "workbench" rectangle to current bounds
- _boundsAfterResize.X = _boundsBeforeResize.X;
- _boundsAfterResize.Y = _boundsBeforeResize.Y;
- _boundsAfterResize.Width = _boundsBeforeResize.Width;
- _boundsAfterResize.Height = _boundsBeforeResize.Height;
-
- // calculate scaled rectangle
- ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions());
-
- // apply scaled bounds to this DrawableContainer
- Owner.ApplyBounds(_boundsAfterResize);
-
- Owner.Invalidate();
- }
-
- ///
- /// Return the location of the adorner
- ///
- public override Point Location
- {
- get
- {
- int x = 0, y = 0;
- switch (Position)
- {
- case Positions.TopLeft:
- x = Owner.Left;
- y = Owner.Top;
- break;
- case Positions.BottomLeft:
- x = Owner.Left;
- y = Owner.Top + Owner.Height;
- break;
- case Positions.MiddleLeft:
- x = Owner.Left;
- y = Owner.Top + (Owner.Height / 2);
- break;
- case Positions.TopCenter:
- x = Owner.Left + (Owner.Width / 2);
- y = Owner.Top;
- break;
- case Positions.BottomCenter:
- x = Owner.Left + (Owner.Width / 2);
- y = Owner.Top + Owner.Height;
- break;
- case Positions.TopRight:
- x = Owner.Left + Owner.Width;
- y = Owner.Top;
- break;
- case Positions.BottomRight:
- x = Owner.Left + Owner.Width;
- y = Owner.Top + Owner.Height;
- break;
- case Positions.MiddleRight:
- x = Owner.Left + Owner.Width;
- y = Owner.Top + (Owner.Height / 2);
- break;
- }
-
- return new Point(x, y);
- }
- }
-
- ///
- /// Draw the adorner
- ///
- /// PaintEventArgs
- public override void Paint(PaintEventArgs paintEventArgs)
- {
- Graphics targetGraphics = paintEventArgs.Graphics;
-
- var bounds = BoundsOnSurface;
- GraphicsState state = targetGraphics.Save();
-
- targetGraphics.CompositingMode = CompositingMode.SourceCopy;
-
- targetGraphics.FillRectangle(Brushes.Black, bounds);
- targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds);
- targetGraphics.Restore(state);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing.Adorners
+{
+ ///
+ /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble
+ ///
+ public class ResizeAdorner : AbstractAdorner
+ {
+ private Rectangle _boundsBeforeResize = Rectangle.Empty;
+ private RectangleF _boundsAfterResize = RectangleF.Empty;
+
+ public Positions Position { get; private set; }
+
+ public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner)
+ {
+ Position = position;
+ }
+
+ ///
+ /// Returns the cursor for when the mouse is over the adorner
+ ///
+ public override Cursor Cursor
+ {
+ get
+ {
+ bool isNotSwitched = Owner.Width >= 0;
+ if (Owner.Height < 0)
+ {
+ isNotSwitched = !isNotSwitched;
+ }
+
+ switch (Position)
+ {
+ case Positions.TopLeft:
+ case Positions.BottomRight:
+ return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW;
+ case Positions.TopRight:
+ case Positions.BottomLeft:
+ return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE;
+ case Positions.MiddleLeft:
+ case Positions.MiddleRight:
+ return Cursors.SizeWE;
+ case Positions.TopCenter:
+ case Positions.BottomCenter:
+ return Cursors.SizeNS;
+ default:
+ return Cursors.SizeAll;
+ }
+ }
+ }
+
+ ///
+ /// Handle the mouse down
+ ///
+ ///
+ ///
+ public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
+ {
+ EditStatus = EditStatus.RESIZING;
+ _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height);
+ _boundsAfterResize = _boundsBeforeResize;
+ }
+
+ ///
+ /// Handle the mouse move
+ ///
+ ///
+ ///
+ public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
+ {
+ if (EditStatus != EditStatus.RESIZING)
+ {
+ return;
+ }
+
+ Owner.Invalidate();
+ Owner.MakeBoundsChangeUndoable(false);
+
+ // reset "workbench" rectangle to current bounds
+ _boundsAfterResize.X = _boundsBeforeResize.X;
+ _boundsAfterResize.Y = _boundsBeforeResize.Y;
+ _boundsAfterResize.Width = _boundsBeforeResize.Width;
+ _boundsAfterResize.Height = _boundsBeforeResize.Height;
+
+ // calculate scaled rectangle
+ ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions());
+
+ // apply scaled bounds to this DrawableContainer
+ Owner.ApplyBounds(_boundsAfterResize);
+
+ Owner.Invalidate();
+ }
+
+ ///
+ /// Return the location of the adorner
+ ///
+ public override Point Location
+ {
+ get
+ {
+ int x = 0, y = 0;
+ switch (Position)
+ {
+ case Positions.TopLeft:
+ x = Owner.Left;
+ y = Owner.Top;
+ break;
+ case Positions.BottomLeft:
+ x = Owner.Left;
+ y = Owner.Top + Owner.Height;
+ break;
+ case Positions.MiddleLeft:
+ x = Owner.Left;
+ y = Owner.Top + (Owner.Height / 2);
+ break;
+ case Positions.TopCenter:
+ x = Owner.Left + (Owner.Width / 2);
+ y = Owner.Top;
+ break;
+ case Positions.BottomCenter:
+ x = Owner.Left + (Owner.Width / 2);
+ y = Owner.Top + Owner.Height;
+ break;
+ case Positions.TopRight:
+ x = Owner.Left + Owner.Width;
+ y = Owner.Top;
+ break;
+ case Positions.BottomRight:
+ x = Owner.Left + Owner.Width;
+ y = Owner.Top + Owner.Height;
+ break;
+ case Positions.MiddleRight:
+ x = Owner.Left + Owner.Width;
+ y = Owner.Top + (Owner.Height / 2);
+ break;
+ }
+
+ return new Point(x, y);
+ }
+ }
+
+ ///
+ /// Draw the adorner
+ ///
+ /// PaintEventArgs
+ public override void Paint(PaintEventArgs paintEventArgs)
+ {
+ Graphics targetGraphics = paintEventArgs.Graphics;
+
+ var bounds = BoundsOnSurface;
+ GraphicsState state = targetGraphics.Save();
+
+ targetGraphics.CompositingMode = CompositingMode.SourceCopy;
+
+ targetGraphics.FillRectangle(Brushes.Black, bounds);
+ targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds);
+ targetGraphics.Restore(state);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs
similarity index 98%
rename from src/Greenshot/Drawing/Adorners/TargetAdorner.cs
rename to src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs
index 8528a27ed..0dec40a5f 100644
--- a/src/Greenshot/Drawing/Adorners/TargetAdorner.cs
+++ b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs
@@ -24,7 +24,7 @@ using System.Drawing.Drawing2D;
using System.Windows.Forms;
using Greenshot.Base.Interfaces.Drawing;
-namespace Greenshot.Drawing.Adorners
+namespace Greenshot.Editor.Drawing.Adorners
{
///
/// This implements the special "gripper" for the Speech-Bubble tail
diff --git a/src/Greenshot/Drawing/ArrowContainer.cs b/src/Greenshot.Editor/Drawing/ArrowContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/ArrowContainer.cs
rename to src/Greenshot.Editor/Drawing/ArrowContainer.cs
index ef855019a..f285d28bc 100644
--- a/src/Greenshot/Drawing/ArrowContainer.cs
+++ b/src/Greenshot.Editor/Drawing/ArrowContainer.cs
@@ -1,163 +1,163 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of LineContainer.
- ///
- [Serializable()]
- public class ArrowContainer : LineContainer
- {
- public enum ArrowHeadCombination
- {
- NONE,
- START_POINT,
- END_POINT,
- BOTH
- };
-
- private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6);
-
- public ArrowContainer(Surface parent) : base(parent)
- {
- }
-
- ///
- /// Do not use the base, just override so we have our own defaults
- ///
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 2);
- AddField(GetType(), FieldType.ARROWHEADS, 2);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
- AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
- AddField(GetType(), FieldType.SHADOW, true);
- AddField(GetType(), FieldType.ARROWHEADS, ArrowHeadCombination.END_POINT);
- }
-
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
-
- if (lineThickness > 0)
- {
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- ArrowHeadCombination heads = (ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS);
- if (lineThickness > 0)
- {
- if (shadow)
- {
- //draw shadow first
- int basealpha = 100;
- int alpha = basealpha;
- int steps = 5;
- int currentStep = 1;
- while (currentStep <= steps)
- {
- using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
- SetArrowHeads(heads, shadowCapPen);
-
- graphics.DrawLine(shadowCapPen,
- Left + currentStep,
- Top + currentStep,
- Left + currentStep + Width,
- Top + currentStep + Height);
-
- currentStep++;
- alpha -= basealpha / steps;
- }
- }
-
- using Pen pen = new Pen(lineColor, lineThickness);
- SetArrowHeads(heads, pen);
- graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height);
- }
- }
- }
-
- private void SetArrowHeads(ArrowHeadCombination heads, Pen pen)
- {
- if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT)
- {
- pen.CustomStartCap = ARROW_CAP;
- }
-
- if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT)
- {
- pen.CustomEndCap = ARROW_CAP;
- }
- }
-
- public override Rectangle DrawingBounds
- {
- get
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- if (lineThickness > 0)
- {
- using Pen pen = new Pen(Color.White)
- {
- Width = lineThickness
- };
- SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen);
- using GraphicsPath path = new GraphicsPath();
- path.AddLine(Left, Top, Left + Width, Top + Height);
- using Matrix matrix = new Matrix();
- Rectangle drawingBounds = Rectangle.Round(path.GetBounds(matrix, pen));
- drawingBounds.Inflate(2, 2);
- return drawingBounds;
- }
-
- return Rectangle.Empty;
- }
- }
-
- public override bool ClickableAt(int x, int y)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
- if (lineThickness > 0)
- {
- using Pen pen = new Pen(Color.White)
- {
- Width = lineThickness
- };
- SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen);
- using GraphicsPath path = new GraphicsPath();
- path.AddLine(Left, Top, Left + Width, Top + Height);
- return path.IsOutlineVisible(x, y, pen);
- }
-
- return false;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of LineContainer.
+ ///
+ [Serializable()]
+ public class ArrowContainer : LineContainer
+ {
+ public enum ArrowHeadCombination
+ {
+ NONE,
+ START_POINT,
+ END_POINT,
+ BOTH
+ };
+
+ private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6);
+
+ public ArrowContainer(Surface parent) : base(parent)
+ {
+ }
+
+ ///
+ /// Do not use the base, just override so we have our own defaults
+ ///
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 2);
+ AddField(GetType(), FieldType.ARROWHEADS, 2);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
+ AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
+ AddField(GetType(), FieldType.SHADOW, true);
+ AddField(GetType(), FieldType.ARROWHEADS, ArrowHeadCombination.END_POINT);
+ }
+
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+
+ if (lineThickness > 0)
+ {
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ ArrowHeadCombination heads = (ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS);
+ if (lineThickness > 0)
+ {
+ if (shadow)
+ {
+ //draw shadow first
+ int basealpha = 100;
+ int alpha = basealpha;
+ int steps = 5;
+ int currentStep = 1;
+ while (currentStep <= steps)
+ {
+ using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
+ SetArrowHeads(heads, shadowCapPen);
+
+ graphics.DrawLine(shadowCapPen,
+ Left + currentStep,
+ Top + currentStep,
+ Left + currentStep + Width,
+ Top + currentStep + Height);
+
+ currentStep++;
+ alpha -= basealpha / steps;
+ }
+ }
+
+ using Pen pen = new Pen(lineColor, lineThickness);
+ SetArrowHeads(heads, pen);
+ graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height);
+ }
+ }
+ }
+
+ private void SetArrowHeads(ArrowHeadCombination heads, Pen pen)
+ {
+ if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT)
+ {
+ pen.CustomStartCap = ARROW_CAP;
+ }
+
+ if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT)
+ {
+ pen.CustomEndCap = ARROW_CAP;
+ }
+ }
+
+ public override Rectangle DrawingBounds
+ {
+ get
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ if (lineThickness > 0)
+ {
+ using Pen pen = new Pen(Color.White)
+ {
+ Width = lineThickness
+ };
+ SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen);
+ using GraphicsPath path = new GraphicsPath();
+ path.AddLine(Left, Top, Left + Width, Top + Height);
+ using Matrix matrix = new Matrix();
+ Rectangle drawingBounds = Rectangle.Round(path.GetBounds(matrix, pen));
+ drawingBounds.Inflate(2, 2);
+ return drawingBounds;
+ }
+
+ return Rectangle.Empty;
+ }
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
+ if (lineThickness > 0)
+ {
+ using Pen pen = new Pen(Color.White)
+ {
+ Width = lineThickness
+ };
+ SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen);
+ using GraphicsPath path = new GraphicsPath();
+ path.AddLine(Left, Top, Left + Width, Top + Height);
+ return path.IsOutlineVisible(x, y, pen);
+ }
+
+ return false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs
similarity index 95%
rename from src/Greenshot/Drawing/CropContainer.cs
rename to src/Greenshot.Editor/Drawing/CropContainer.cs
index 1ec022207..1aa4e06c2 100644
--- a/src/Greenshot/Drawing/CropContainer.cs
+++ b/src/Greenshot.Editor/Drawing/CropContainer.cs
@@ -1,108 +1,108 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System.Drawing;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of CropContainer.
- ///
- public class CropContainer : DrawableContainer
- {
- public CropContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- Init();
- }
-
- private void Init()
- {
- CreateDefaultAdorners();
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE);
- }
-
- public override void Invalidate()
- {
- _parent?.Invalidate();
- }
-
- ///
- /// 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)
- ///
- public override Rectangle DrawingBounds
- {
- get
- {
- if (_parent?.Image is { } image)
- {
- return new Rectangle(0, 0, image.Width, image.Height);
- }
-
- return Rectangle.Empty;
- }
- }
-
- public override void Draw(Graphics g, RenderMode rm)
- {
- if (_parent == null)
- {
- 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);
- Size imageSize = _parent.Image.Size;
-
- 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)));
- }
-
- ///
- /// No context menu for the CropContainer
- ///
- public override bool HasContextMenu => false;
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.Drawing;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of CropContainer.
+ ///
+ public class CropContainer : DrawableContainer
+ {
+ public CropContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ Init();
+ }
+
+ private void Init()
+ {
+ CreateDefaultAdorners();
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE);
+ }
+
+ public override void Invalidate()
+ {
+ _parent?.Invalidate();
+ }
+
+ ///
+ /// 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)
+ ///
+ public override Rectangle DrawingBounds
+ {
+ get
+ {
+ if (_parent?.Image is { } image)
+ {
+ return new Rectangle(0, 0, image.Width, image.Height);
+ }
+
+ return Rectangle.Empty;
+ }
+ }
+
+ public override void Draw(Graphics g, RenderMode rm)
+ {
+ if (_parent == null)
+ {
+ 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);
+ Size imageSize = _parent.Image.Size;
+
+ 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)));
+ }
+
+ ///
+ /// No context menu for the CropContainer
+ ///
+ public override bool HasContextMenu => false;
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/CursorContainer.cs b/src/Greenshot.Editor/Drawing/CursorContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/CursorContainer.cs
rename to src/Greenshot.Editor/Drawing/CursorContainer.cs
index ec4568000..d2e19adba 100644
--- a/src/Greenshot/Drawing/CursorContainer.cs
+++ b/src/Greenshot.Editor/Drawing/CursorContainer.cs
@@ -1,128 +1,128 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.IO;
-using System.Windows.Forms;
-using System.Drawing.Drawing2D;
-using log4net;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of CursorContainer.
- ///
- [Serializable]
- public class CursorContainer : DrawableContainer, ICursorContainer
- {
- private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer));
-
- protected Cursor cursor;
-
- public CursorContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- Init();
- }
-
- private void Init()
- {
- CreateDefaultAdorners();
- }
-
- public CursorContainer(Surface parent, string filename) : this(parent)
- {
- Load(filename);
- }
-
- public Cursor Cursor
- {
- set
- {
- if (cursor != null)
- {
- cursor.Dispose();
- }
-
- // Clone cursor (is this correct??)
- cursor = new Cursor(value.CopyHandle());
- Width = value.Size.Width;
- Height = value.Size.Height;
- }
- get { return cursor; }
- }
-
- ///
- /// This Dispose is called from the Dispose and the Destructor.
- /// When disposing==true all non-managed resources should be freed too!
- ///
- ///
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (cursor != null)
- {
- cursor.Dispose();
- }
- }
-
- cursor = null;
- base.Dispose(disposing);
- }
-
- public void Load(string filename)
- {
- if (!File.Exists(filename))
- {
- return;
- }
-
- using Cursor fileCursor = new Cursor(filename);
- Cursor = fileCursor;
- LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
- }
-
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- if (cursor == null)
- {
- return;
- }
-
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
- graphics.CompositingQuality = CompositingQuality.Default;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
- cursor.DrawStretched(graphics, Bounds);
- }
-
- public override Size DefaultSize => cursor?.Size ?? new Size(16, 16);
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Windows.Forms;
+using Greenshot.Base.Interfaces.Drawing;
+using log4net;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of CursorContainer.
+ ///
+ [Serializable]
+ public class CursorContainer : DrawableContainer, ICursorContainer
+ {
+ private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer));
+
+ protected Cursor cursor;
+
+ public CursorContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ Init();
+ }
+
+ private void Init()
+ {
+ CreateDefaultAdorners();
+ }
+
+ public CursorContainer(Surface parent, string filename) : this(parent)
+ {
+ Load(filename);
+ }
+
+ public Cursor Cursor
+ {
+ set
+ {
+ if (cursor != null)
+ {
+ cursor.Dispose();
+ }
+
+ // Clone cursor (is this correct??)
+ cursor = new Cursor(value.CopyHandle());
+ Width = value.Size.Width;
+ Height = value.Size.Height;
+ }
+ get { return cursor; }
+ }
+
+ ///
+ /// This Dispose is called from the Dispose and the Destructor.
+ /// When disposing==true all non-managed resources should be freed too!
+ ///
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (cursor != null)
+ {
+ cursor.Dispose();
+ }
+ }
+
+ cursor = null;
+ base.Dispose(disposing);
+ }
+
+ public void Load(string filename)
+ {
+ if (!File.Exists(filename))
+ {
+ return;
+ }
+
+ using Cursor fileCursor = new Cursor(filename);
+ Cursor = fileCursor;
+ LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
+ }
+
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ if (cursor == null)
+ {
+ return;
+ }
+
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
+ graphics.CompositingQuality = CompositingQuality.Default;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+ cursor.DrawStretched(graphics, Bounds);
+ }
+
+ public override Size DefaultSize => cursor?.Size ?? new Size(16, 16);
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs
similarity index 95%
rename from src/Greenshot/Drawing/DrawableContainer.cs
rename to src/Greenshot.Editor/Drawing/DrawableContainer.cs
index 95ca776d7..b7202b23e 100644
--- a/src/Greenshot/Drawing/DrawableContainer.cs
+++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs
@@ -1,670 +1,670 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Configuration;
-using Greenshot.Drawing.Adorners;
-using Greenshot.Drawing.Fields;
-using Greenshot.Drawing.Filters;
-using Greenshot.Helpers;
-using Greenshot.Memento;
-using log4net;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Linq;
-using System.Runtime.Serialization;
-using Greenshot.Base.IniFile;
-using Greenshot.Base.Interfaces;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Base.Interfaces.Drawing.Adorners;
-
-namespace Greenshot.Drawing
-{
- ///
- /// represents a rectangle, ellipse, label or whatever. Can contain filters, too.
- /// serializable for clipboard support
- /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call
- /// OnPropertyChanged whenever a public property has been changed.
- ///
- [Serializable]
- public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer
- {
- private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer));
- protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection();
- private const int M11 = 0;
- private const int M22 = 3;
-
- [OnDeserialized]
- private void OnDeserializedInit(StreamingContext context)
- {
- _adorners = new List();
- OnDeserialized(context);
- }
-
- ///
- /// Override to implement your own deserialization logic, like initializing properties which are not serialized
- ///
- ///
- protected virtual void OnDeserialized(StreamingContext streamingContext)
- {
- }
-
- protected EditStatus _defaultEditMode = EditStatus.DRAWING;
-
- public EditStatus DefaultEditMode
- {
- get { return _defaultEditMode; }
- }
-
- ///
- /// The public accessible Dispose
- /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice
- ///
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (!disposing)
- {
- return;
- }
-
- _parent?.FieldAggregator?.UnbindElement(this);
- }
-
- ~DrawableContainer()
- {
- Dispose(false);
- }
-
- [NonSerialized] private PropertyChangedEventHandler _propertyChanged;
-
- public event PropertyChangedEventHandler PropertyChanged
- {
- add => _propertyChanged += value;
- remove => _propertyChanged -= value;
- }
-
- public IList Filters
- {
- get
- {
- List ret = new List();
- foreach (IFieldHolder c in Children)
- {
- if (c is IFilter)
- {
- ret.Add(c as IFilter);
- }
- }
-
- return ret;
- }
- }
-
- [NonSerialized] internal Surface _parent;
-
- public ISurface Parent
- {
- get => _parent;
- set => SwitchParent((Surface) value);
- }
-
- [NonSerialized] private TargetAdorner _targetAdorner;
- public TargetAdorner TargetAdorner => _targetAdorner;
-
- [NonSerialized] private bool _selected;
-
- public bool Selected
- {
- get => _selected;
- set
- {
- _selected = value;
- OnPropertyChanged("Selected");
- }
- }
-
- [NonSerialized] private EditStatus _status = EditStatus.UNDRAWN;
-
- public EditStatus Status
- {
- get => _status;
- set => _status = value;
- }
-
-
- private int left;
-
- public int Left
- {
- get => left;
- set
- {
- if (value == left)
- {
- return;
- }
-
- left = value;
- }
- }
-
- private int top;
-
- public int Top
- {
- get => top;
- set
- {
- if (value == top)
- {
- return;
- }
-
- top = value;
- }
- }
-
- private int width;
-
- public int Width
- {
- get => width;
- set
- {
- if (value == width)
- {
- return;
- }
-
- width = value;
- }
- }
-
- private int height;
-
- public int Height
- {
- get => height;
- set
- {
- if (value == height)
- {
- return;
- }
-
- height = value;
- }
- }
-
- public Point Location
- {
- get => new Point(left, top);
- set
- {
- left = value.X;
- top = value.Y;
- }
- }
-
- public Size Size
- {
- get => new Size(width, height);
- set
- {
- width = value.Width;
- height = value.Height;
- }
- }
-
- ///
- /// List of available Adorners
- ///
- [NonSerialized] private IList _adorners = new List();
-
- public IList Adorners => _adorners;
-
- [NonSerialized]
- // will store current bounds of this DrawableContainer before starting a resize
- protected Rectangle _boundsBeforeResize = Rectangle.Empty;
-
- [NonSerialized]
- // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards)
- protected RectangleF _boundsAfterResize = RectangleF.Empty;
-
- public Rectangle Bounds
- {
- get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- set
- {
- Left = Round(value.Left);
- Top = Round(value.Top);
- Width = Round(value.Width);
- Height = Round(value.Height);
- }
- }
-
- public virtual void ApplyBounds(RectangleF newBounds)
- {
- Left = Round(newBounds.Left);
- Top = Round(newBounds.Top);
- Width = Round(newBounds.Width);
- Height = Round(newBounds.Height);
- }
-
- public DrawableContainer(Surface parent)
- {
- InitializeFields();
- _parent = parent;
- }
-
- public void Add(IFilter filter)
- {
- AddChild(filter);
- }
-
- public void Remove(IFilter filter)
- {
- RemoveChild(filter);
- }
-
- private static int Round(float f)
- {
- if (float.IsPositiveInfinity(f) || f > int.MaxValue / 2) return int.MaxValue / 2;
- if (float.IsNegativeInfinity(f) || f < int.MinValue / 2) return int.MinValue / 2;
- return (int) Math.Round(f);
- }
-
- private bool accountForShadowChange;
-
- public virtual Rectangle DrawingBounds
- {
- get
- {
- foreach (IFilter filter in Filters)
- {
- if (filter.Invert)
- {
- return new Rectangle(Point.Empty, _parent.Image.Size);
- }
- }
-
- // Take a base safety margin
- int lineThickness = 5;
-
- // add adorner size
- lineThickness += Adorners.Max(adorner => Math.Max(adorner.Bounds.Width, adorner.Bounds.Height));
-
- if (HasField(FieldType.LINE_THICKNESS))
- {
- lineThickness += GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- }
-
- int offset = lineThickness / 2;
-
- int shadow = 0;
- if (accountForShadowChange || (HasField(FieldType.SHADOW) && GetFieldValueAsBool(FieldType.SHADOW)))
- {
- accountForShadowChange = false;
- shadow += 10;
- }
-
- return new Rectangle(Bounds.Left - offset, Bounds.Top - offset, Bounds.Width + lineThickness + shadow, Bounds.Height + lineThickness + shadow);
- }
- }
-
- public virtual void Invalidate()
- {
- if (Status != EditStatus.UNDRAWN)
- {
- _parent?.InvalidateElements(DrawingBounds);
- }
- }
-
- public virtual bool InitContent()
- {
- return true;
- }
-
- public virtual void OnDoubleClick()
- {
- }
-
- ///
- /// Initialize a target gripper
- ///
- protected void InitAdorner(Color gripperColor, Point location)
- {
- _targetAdorner = new TargetAdorner(this, location);
- Adorners.Add(_targetAdorner);
- }
-
- ///
- /// Create the default adorners for a rectangle based container
- ///
- protected void CreateDefaultAdorners()
- {
- if (Adorners.Count > 0)
- {
- LOG.Warn("Adorners are already defined!");
- }
-
- // Create the GripperAdorners
- Adorners.Add(new ResizeAdorner(this, Positions.TopLeft));
- Adorners.Add(new ResizeAdorner(this, Positions.TopCenter));
- Adorners.Add(new ResizeAdorner(this, Positions.TopRight));
- Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft));
- Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter));
- Adorners.Add(new ResizeAdorner(this, Positions.BottomRight));
- Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft));
- Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight));
- }
-
- public bool hasFilters => Filters.Count > 0;
-
- public abstract void Draw(Graphics graphics, RenderMode renderMode);
-
- public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle)
- {
- if (Children.Count > 0)
- {
- if (Status != EditStatus.IDLE)
- {
- DrawSelectionBorder(graphics, Bounds);
- }
- else
- {
- if (clipRectangle.Width != 0 && clipRectangle.Height != 0)
- {
- foreach (IFilter filter in Filters)
- {
- if (filter.Invert)
- {
- filter.Apply(graphics, bmp, Bounds, renderMode);
- }
- else
- {
- Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size);
- drawingRect.Intersect(clipRectangle);
- if (filter is MagnifierFilter)
- {
- // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially
- // what we should actually do to resolve this is add a better magnifier which is not that special
- filter.Apply(graphics, bmp, Bounds, renderMode);
- }
- else
- {
- filter.Apply(graphics, bmp, drawingRect, renderMode);
- }
- }
- }
- }
- }
- }
-
- Draw(graphics, renderMode);
- }
-
- ///
- /// Adjust UI elements to the supplied DPI settings
- ///
- /// uint with dpi value
- public void AdjustToDpi(uint dpi)
- {
- foreach (var adorner in Adorners)
- {
- adorner.AdjustToDpi(dpi);
- }
- }
-
- public virtual bool Contains(int x, int y)
- {
- return Bounds.Contains(x, y);
- }
-
- public virtual bool ClickableAt(int x, int y)
- {
- Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- r.Inflate(5, 5);
- return r.Contains(x, y);
- }
-
- protected void DrawSelectionBorder(Graphics g, Rectangle rect)
- {
- using Pen pen = new Pen(Color.MediumSeaGreen)
- {
- DashPattern = new float[]
- {
- 1, 2
- },
- Width = 1
- };
- g.DrawRectangle(pen, rect);
- }
-
-
- public void ResizeTo(int width, int height, int anchorPosition)
- {
- Width = width;
- Height = height;
- }
-
- ///
- /// Make a following bounds change on this drawablecontainer undoable!
- ///
- /// true means allow the moves to be merged
- public void MakeBoundsChangeUndoable(bool allowMerge)
- {
- _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge);
- }
-
- public void MoveBy(int dx, int dy)
- {
- Left += dx;
- Top += dy;
- }
-
- ///
- /// A handler for the MouseDown, used if you don't want the surface to handle this for you
- ///
- /// current mouse x
- /// current mouse y
- /// true if the event is handled, false if the surface needs to handle it
- public virtual bool HandleMouseDown(int x, int y)
- {
- Left = _boundsBeforeResize.X = x;
- Top = _boundsBeforeResize.Y = y;
- return true;
- }
-
- ///
- /// A handler for the MouseMove, used if you don't want the surface to handle this for you
- ///
- /// current mouse x
- /// current mouse y
- /// true if the event is handled, false if the surface needs to handle it
- public virtual bool HandleMouseMove(int x, int y)
- {
- Invalidate();
-
- // reset "workrbench" rectangle to current bounds
- _boundsAfterResize.X = _boundsBeforeResize.Left;
- _boundsAfterResize.Y = _boundsBeforeResize.Top;
- _boundsAfterResize.Width = x - _boundsAfterResize.Left;
- _boundsAfterResize.Height = y - _boundsAfterResize.Top;
-
- ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor());
-
- // apply scaled bounds to this DrawableContainer
- ApplyBounds(_boundsAfterResize);
-
- Invalidate();
- return true;
- }
-
- ///
- /// A handler for the MouseUp
- ///
- /// current mouse x
- /// current mouse y
- public virtual void HandleMouseUp(int x, int y)
- {
- }
-
- protected virtual void SwitchParent(Surface newParent)
- {
- if (newParent == Parent)
- {
- return;
- }
-
- _parent?.FieldAggregator?.UnbindElement(this);
-
- _parent = newParent;
- foreach (IFilter filter in Filters)
- {
- filter.Parent = this;
- }
- }
-
- protected void OnPropertyChanged(string propertyName)
- {
- if (_propertyChanged != null)
- {
- _propertyChanged(this, new PropertyChangedEventArgs(propertyName));
- Invalidate();
- }
- }
-
- ///
- /// This method will be called before a field is changes.
- /// Using this makes it possible to invalidate the object as is before changing.
- ///
- /// The field to be changed
- /// The new value
- public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue)
- {
- _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true);
- Invalidate();
- }
-
- ///
- /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!)
- ///
- ///
- ///
- public void HandleFieldChanged(object sender, FieldChangedEventArgs e)
- {
- LOG.DebugFormat("Field {0} changed", e.Field.FieldType);
- if (Equals(e.Field.FieldType, FieldType.SHADOW))
- {
- accountForShadowChange = true;
- }
- }
-
- ///
- /// Retrieve the Y scale from the matrix
- ///
- ///
- ///
- public static float CalculateScaleY(Matrix matrix)
- {
- return matrix.Elements[M22];
- }
-
- ///
- /// Retrieve the X scale from the matrix
- ///
- ///
- ///
- public static float CalculateScaleX(Matrix matrix)
- {
- return matrix.Elements[M11];
- }
-
- ///
- /// Retrieve the rotation angle from the matrix
- ///
- ///
- ///
- public static int CalculateAngle(Matrix matrix)
- {
- const int M11 = 0;
- const int M21 = 2;
- var radians = Math.Atan2(matrix.Elements[M21], matrix.Elements[M11]);
- return (int) -Math.Round(radians * 180 / Math.PI);
- }
-
- ///
- /// This method is called on a DrawableContainers when:
- /// 1) The capture on the surface is modified in such a way, that the elements would not be placed correctly.
- /// 2) Currently not implemented: an element needs to be moved, scaled or rotated.
- /// This basis implementation makes sure the coordinates of the element, including the TargetGripper, is correctly rotated/scaled/translated.
- /// But this implementation doesn't take care of any changes to the content!!
- ///
- ///
- public virtual void Transform(Matrix matrix)
- {
- if (matrix == null)
- {
- return;
- }
-
- Point topLeft = new Point(Left, Top);
- Point bottomRight = new Point(Left + Width, Top + Height);
- Point[] points = new[]
- {
- topLeft, bottomRight
- };
- matrix.TransformPoints(points);
-
- Left = points[0].X;
- Top = points[0].Y;
- Width = points[1].X - points[0].X;
- Height = points[1].Y - points[0].Y;
- }
-
- protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor()
- {
- return ScaleHelper.ShapeAngleRoundBehavior.Instance;
- }
-
- public virtual bool HasContextMenu => true;
-
- public virtual bool HasDefaultSize => false;
-
- public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size");
-
- ///
- /// Allows to override the initializing of the fields, so we can actually have our own defaults
- ///
- protected virtual void InitializeFields()
- {
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+using System.Runtime.Serialization;
+using Greenshot.Base.IniFile;
+using Greenshot.Base.Interfaces;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Base.Interfaces.Drawing.Adorners;
+using Greenshot.Editor.Configuration;
+using Greenshot.Editor.Drawing.Adorners;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Drawing.Filters;
+using Greenshot.Editor.Helpers;
+using Greenshot.Editor.Memento;
+using log4net;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// represents a rectangle, ellipse, label or whatever. Can contain filters, too.
+ /// serializable for clipboard support
+ /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call
+ /// OnPropertyChanged whenever a public property has been changed.
+ ///
+ [Serializable]
+ public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer
+ {
+ private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer));
+ protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection();
+ private const int M11 = 0;
+ private const int M22 = 3;
+
+ [OnDeserialized]
+ private void OnDeserializedInit(StreamingContext context)
+ {
+ _adorners = new List();
+ OnDeserialized(context);
+ }
+
+ ///
+ /// Override to implement your own deserialization logic, like initializing properties which are not serialized
+ ///
+ ///
+ protected virtual void OnDeserialized(StreamingContext streamingContext)
+ {
+ }
+
+ protected EditStatus _defaultEditMode = EditStatus.DRAWING;
+
+ public EditStatus DefaultEditMode
+ {
+ get { return _defaultEditMode; }
+ }
+
+ ///
+ /// The public accessible Dispose
+ /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposing)
+ {
+ return;
+ }
+
+ _parent?.FieldAggregator?.UnbindElement(this);
+ }
+
+ ~DrawableContainer()
+ {
+ Dispose(false);
+ }
+
+ [NonSerialized] private PropertyChangedEventHandler _propertyChanged;
+
+ public event PropertyChangedEventHandler PropertyChanged
+ {
+ add => _propertyChanged += value;
+ remove => _propertyChanged -= value;
+ }
+
+ public IList Filters
+ {
+ get
+ {
+ List ret = new List();
+ foreach (IFieldHolder c in Children)
+ {
+ if (c is IFilter)
+ {
+ ret.Add(c as IFilter);
+ }
+ }
+
+ return ret;
+ }
+ }
+
+ [NonSerialized] internal Surface _parent;
+
+ public ISurface Parent
+ {
+ get => _parent;
+ set => SwitchParent((Surface) value);
+ }
+
+ [NonSerialized] private TargetAdorner _targetAdorner;
+ public TargetAdorner TargetAdorner => _targetAdorner;
+
+ [NonSerialized] private bool _selected;
+
+ public bool Selected
+ {
+ get => _selected;
+ set
+ {
+ _selected = value;
+ OnPropertyChanged("Selected");
+ }
+ }
+
+ [NonSerialized] private EditStatus _status = EditStatus.UNDRAWN;
+
+ public EditStatus Status
+ {
+ get => _status;
+ set => _status = value;
+ }
+
+
+ private int left;
+
+ public int Left
+ {
+ get => left;
+ set
+ {
+ if (value == left)
+ {
+ return;
+ }
+
+ left = value;
+ }
+ }
+
+ private int top;
+
+ public int Top
+ {
+ get => top;
+ set
+ {
+ if (value == top)
+ {
+ return;
+ }
+
+ top = value;
+ }
+ }
+
+ private int width;
+
+ public int Width
+ {
+ get => width;
+ set
+ {
+ if (value == width)
+ {
+ return;
+ }
+
+ width = value;
+ }
+ }
+
+ private int height;
+
+ public int Height
+ {
+ get => height;
+ set
+ {
+ if (value == height)
+ {
+ return;
+ }
+
+ height = value;
+ }
+ }
+
+ public Point Location
+ {
+ get => new Point(left, top);
+ set
+ {
+ left = value.X;
+ top = value.Y;
+ }
+ }
+
+ public Size Size
+ {
+ get => new Size(width, height);
+ set
+ {
+ width = value.Width;
+ height = value.Height;
+ }
+ }
+
+ ///
+ /// List of available Adorners
+ ///
+ [NonSerialized] private IList _adorners = new List();
+
+ public IList Adorners => _adorners;
+
+ [NonSerialized]
+ // will store current bounds of this DrawableContainer before starting a resize
+ protected Rectangle _boundsBeforeResize = Rectangle.Empty;
+
+ [NonSerialized]
+ // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards)
+ protected RectangleF _boundsAfterResize = RectangleF.Empty;
+
+ public Rectangle Bounds
+ {
+ get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ set
+ {
+ Left = Round(value.Left);
+ Top = Round(value.Top);
+ Width = Round(value.Width);
+ Height = Round(value.Height);
+ }
+ }
+
+ public virtual void ApplyBounds(RectangleF newBounds)
+ {
+ Left = Round(newBounds.Left);
+ Top = Round(newBounds.Top);
+ Width = Round(newBounds.Width);
+ Height = Round(newBounds.Height);
+ }
+
+ public DrawableContainer(Surface parent)
+ {
+ InitializeFields();
+ _parent = parent;
+ }
+
+ public void Add(IFilter filter)
+ {
+ AddChild(filter);
+ }
+
+ public void Remove(IFilter filter)
+ {
+ RemoveChild(filter);
+ }
+
+ private static int Round(float f)
+ {
+ if (float.IsPositiveInfinity(f) || f > int.MaxValue / 2) return int.MaxValue / 2;
+ if (float.IsNegativeInfinity(f) || f < int.MinValue / 2) return int.MinValue / 2;
+ return (int) Math.Round(f);
+ }
+
+ private bool accountForShadowChange;
+
+ public virtual Rectangle DrawingBounds
+ {
+ get
+ {
+ foreach (IFilter filter in Filters)
+ {
+ if (filter.Invert)
+ {
+ return new Rectangle(Point.Empty, _parent.Image.Size);
+ }
+ }
+
+ // Take a base safety margin
+ int lineThickness = 5;
+
+ // add adorner size
+ lineThickness += Adorners.Max(adorner => Math.Max(adorner.Bounds.Width, adorner.Bounds.Height));
+
+ if (HasField(FieldType.LINE_THICKNESS))
+ {
+ lineThickness += GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ }
+
+ int offset = lineThickness / 2;
+
+ int shadow = 0;
+ if (accountForShadowChange || (HasField(FieldType.SHADOW) && GetFieldValueAsBool(FieldType.SHADOW)))
+ {
+ accountForShadowChange = false;
+ shadow += 10;
+ }
+
+ return new Rectangle(Bounds.Left - offset, Bounds.Top - offset, Bounds.Width + lineThickness + shadow, Bounds.Height + lineThickness + shadow);
+ }
+ }
+
+ public virtual void Invalidate()
+ {
+ if (Status != EditStatus.UNDRAWN)
+ {
+ _parent?.InvalidateElements(DrawingBounds);
+ }
+ }
+
+ public virtual bool InitContent()
+ {
+ return true;
+ }
+
+ public virtual void OnDoubleClick()
+ {
+ }
+
+ ///
+ /// Initialize a target gripper
+ ///
+ protected void InitAdorner(Color gripperColor, Point location)
+ {
+ _targetAdorner = new TargetAdorner(this, location);
+ Adorners.Add(_targetAdorner);
+ }
+
+ ///
+ /// Create the default adorners for a rectangle based container
+ ///
+ protected void CreateDefaultAdorners()
+ {
+ if (Adorners.Count > 0)
+ {
+ LOG.Warn("Adorners are already defined!");
+ }
+
+ // Create the GripperAdorners
+ Adorners.Add(new ResizeAdorner(this, Positions.TopLeft));
+ Adorners.Add(new ResizeAdorner(this, Positions.TopCenter));
+ Adorners.Add(new ResizeAdorner(this, Positions.TopRight));
+ Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft));
+ Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter));
+ Adorners.Add(new ResizeAdorner(this, Positions.BottomRight));
+ Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft));
+ Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight));
+ }
+
+ public bool hasFilters => Filters.Count > 0;
+
+ public abstract void Draw(Graphics graphics, RenderMode renderMode);
+
+ public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle)
+ {
+ if (Children.Count > 0)
+ {
+ if (Status != EditStatus.IDLE)
+ {
+ DrawSelectionBorder(graphics, Bounds);
+ }
+ else
+ {
+ if (clipRectangle.Width != 0 && clipRectangle.Height != 0)
+ {
+ foreach (IFilter filter in Filters)
+ {
+ if (filter.Invert)
+ {
+ filter.Apply(graphics, bmp, Bounds, renderMode);
+ }
+ else
+ {
+ Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size);
+ drawingRect.Intersect(clipRectangle);
+ if (filter is MagnifierFilter)
+ {
+ // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially
+ // what we should actually do to resolve this is add a better magnifier which is not that special
+ filter.Apply(graphics, bmp, Bounds, renderMode);
+ }
+ else
+ {
+ filter.Apply(graphics, bmp, drawingRect, renderMode);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Draw(graphics, renderMode);
+ }
+
+ ///
+ /// Adjust UI elements to the supplied DPI settings
+ ///
+ /// uint with dpi value
+ public void AdjustToDpi(uint dpi)
+ {
+ foreach (var adorner in Adorners)
+ {
+ adorner.AdjustToDpi(dpi);
+ }
+ }
+
+ public virtual bool Contains(int x, int y)
+ {
+ return Bounds.Contains(x, y);
+ }
+
+ public virtual bool ClickableAt(int x, int y)
+ {
+ Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ r.Inflate(5, 5);
+ return r.Contains(x, y);
+ }
+
+ protected void DrawSelectionBorder(Graphics g, Rectangle rect)
+ {
+ using Pen pen = new Pen(Color.MediumSeaGreen)
+ {
+ DashPattern = new float[]
+ {
+ 1, 2
+ },
+ Width = 1
+ };
+ g.DrawRectangle(pen, rect);
+ }
+
+
+ public void ResizeTo(int width, int height, int anchorPosition)
+ {
+ Width = width;
+ Height = height;
+ }
+
+ ///
+ /// Make a following bounds change on this drawablecontainer undoable!
+ ///
+ /// true means allow the moves to be merged
+ public void MakeBoundsChangeUndoable(bool allowMerge)
+ {
+ _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge);
+ }
+
+ public void MoveBy(int dx, int dy)
+ {
+ Left += dx;
+ Top += dy;
+ }
+
+ ///
+ /// A handler for the MouseDown, used if you don't want the surface to handle this for you
+ ///
+ /// current mouse x
+ /// current mouse y
+ /// true if the event is handled, false if the surface needs to handle it
+ public virtual bool HandleMouseDown(int x, int y)
+ {
+ Left = _boundsBeforeResize.X = x;
+ Top = _boundsBeforeResize.Y = y;
+ return true;
+ }
+
+ ///
+ /// A handler for the MouseMove, used if you don't want the surface to handle this for you
+ ///
+ /// current mouse x
+ /// current mouse y
+ /// true if the event is handled, false if the surface needs to handle it
+ public virtual bool HandleMouseMove(int x, int y)
+ {
+ Invalidate();
+
+ // reset "workrbench" rectangle to current bounds
+ _boundsAfterResize.X = _boundsBeforeResize.Left;
+ _boundsAfterResize.Y = _boundsBeforeResize.Top;
+ _boundsAfterResize.Width = x - _boundsAfterResize.Left;
+ _boundsAfterResize.Height = y - _boundsAfterResize.Top;
+
+ ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor());
+
+ // apply scaled bounds to this DrawableContainer
+ ApplyBounds(_boundsAfterResize);
+
+ Invalidate();
+ return true;
+ }
+
+ ///
+ /// A handler for the MouseUp
+ ///
+ /// current mouse x
+ /// current mouse y
+ public virtual void HandleMouseUp(int x, int y)
+ {
+ }
+
+ protected virtual void SwitchParent(Surface newParent)
+ {
+ if (newParent == Parent)
+ {
+ return;
+ }
+
+ _parent?.FieldAggregator?.UnbindElement(this);
+
+ _parent = newParent;
+ foreach (IFilter filter in Filters)
+ {
+ filter.Parent = this;
+ }
+ }
+
+ protected void OnPropertyChanged(string propertyName)
+ {
+ if (_propertyChanged != null)
+ {
+ _propertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ Invalidate();
+ }
+ }
+
+ ///
+ /// This method will be called before a field is changes.
+ /// Using this makes it possible to invalidate the object as is before changing.
+ ///
+ /// The field to be changed
+ /// The new value
+ public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue)
+ {
+ _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true);
+ Invalidate();
+ }
+
+ ///
+ /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!)
+ ///
+ ///
+ ///
+ public void HandleFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ LOG.DebugFormat("Field {0} changed", e.Field.FieldType);
+ if (Equals(e.Field.FieldType, FieldType.SHADOW))
+ {
+ accountForShadowChange = true;
+ }
+ }
+
+ ///
+ /// Retrieve the Y scale from the matrix
+ ///
+ ///
+ ///
+ public static float CalculateScaleY(Matrix matrix)
+ {
+ return matrix.Elements[M22];
+ }
+
+ ///
+ /// Retrieve the X scale from the matrix
+ ///
+ ///
+ ///
+ public static float CalculateScaleX(Matrix matrix)
+ {
+ return matrix.Elements[M11];
+ }
+
+ ///
+ /// Retrieve the rotation angle from the matrix
+ ///
+ ///
+ ///
+ public static int CalculateAngle(Matrix matrix)
+ {
+ const int M11 = 0;
+ const int M21 = 2;
+ var radians = Math.Atan2(matrix.Elements[M21], matrix.Elements[M11]);
+ return (int) -Math.Round(radians * 180 / Math.PI);
+ }
+
+ ///
+ /// This method is called on a DrawableContainers when:
+ /// 1) The capture on the surface is modified in such a way, that the elements would not be placed correctly.
+ /// 2) Currently not implemented: an element needs to be moved, scaled or rotated.
+ /// This basis implementation makes sure the coordinates of the element, including the TargetGripper, is correctly rotated/scaled/translated.
+ /// But this implementation doesn't take care of any changes to the content!!
+ ///
+ ///
+ public virtual void Transform(Matrix matrix)
+ {
+ if (matrix == null)
+ {
+ return;
+ }
+
+ Point topLeft = new Point(Left, Top);
+ Point bottomRight = new Point(Left + Width, Top + Height);
+ Point[] points = new[]
+ {
+ topLeft, bottomRight
+ };
+ matrix.TransformPoints(points);
+
+ Left = points[0].X;
+ Top = points[0].Y;
+ Width = points[1].X - points[0].X;
+ Height = points[1].Y - points[0].Y;
+ }
+
+ protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor()
+ {
+ return ScaleHelper.ShapeAngleRoundBehavior.Instance;
+ }
+
+ public virtual bool HasContextMenu => true;
+
+ public virtual bool HasDefaultSize => false;
+
+ public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size");
+
+ ///
+ /// Allows to override the initializing of the fields, so we can actually have our own defaults
+ ///
+ protected virtual void InitializeFields()
+ {
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs
similarity index 96%
rename from src/Greenshot/Drawing/DrawableContainerList.cs
rename to src/Greenshot.Editor/Drawing/DrawableContainerList.cs
index 3a50a9ef8..9465d7779 100644
--- a/src/Greenshot/Drawing/DrawableContainerList.cs
+++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs
@@ -1,728 +1,728 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Configuration;
-using Greenshot.Memento;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Threading;
-using System.Windows.Forms;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Forms;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers.
- ///
- [Serializable]
- public class DrawableContainerList : List, IDrawableContainerList
- {
- private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm));
-
- public Guid ParentID { get; private set; }
-
- public DrawableContainerList()
- {
- }
-
- public DrawableContainerList(Guid parentId)
- {
- ParentID = parentId;
- }
-
- public EditStatus Status
- {
- get { return this[Count - 1].Status; }
- set
- {
- foreach (var dc in this)
- {
- dc.Status = value;
- }
- }
- }
-
- public List AsIDrawableContainerList()
- {
- List interfaceList = new List();
- foreach (IDrawableContainer container in this)
- {
- interfaceList.Add(container);
- }
-
- return interfaceList;
- }
-
- ///
- /// Gets or sets the selection status of the elements.
- /// If several elements are in the list, true is only returned when all elements are selected.
- ///
- public bool Selected
- {
- get
- {
- bool ret = true;
- foreach (var dc in this)
- {
- ret &= dc.Selected;
- }
-
- return ret;
- }
- set
- {
- foreach (var dc in this)
- {
- dc.Selected = value;
- }
- }
- }
-
- ///
- /// Gets or sets the parent control of the elements in the list.
- /// If there are several elements, the parent control of the last added is returned.
- ///
- public ISurface Parent
- {
- get
- {
- if (Count > 0)
- {
- return this[Count - 1].Parent;
- }
-
- return null;
- }
- set
- {
- ParentID = value?.ID ?? Guid.NewGuid();
- foreach (var drawableContainer in this)
- {
- var dc = (DrawableContainer) drawableContainer;
- dc.Parent = value;
- }
- }
- }
-
- ///
- /// Make a following bounds change on this containerlist undoable!
- ///
- /// true means allow the moves to be merged
- public void MakeBoundsChangeUndoable(bool allowMerge)
- {
- if (Count > 0 && Parent != null)
- {
- var clone = new DrawableContainerList();
- clone.AddRange(this);
- Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge);
- }
- }
-
- ///
- /// Apply matrix to all elements
- ///
- public void Transform(Matrix matrix)
- {
- // Track modifications
- bool modified = false;
- Invalidate();
- foreach (var dc in this)
- {
- dc.Transform(matrix);
- modified = true;
- }
-
- // Invalidate after
- Invalidate();
- // If we moved something, tell the surface it's modified!
- if (modified)
- {
- Parent.Modified = true;
- }
- }
-
- ///
- /// Moves all elements in the list by the given amount of pixels.
- ///
- /// pixels to move horizontally
- /// pixels to move vertically
- public void MoveBy(int dx, int dy)
- {
- // Track modifications
- bool modified = false;
-
- // Invalidate before moving, otherwise the old locations aren't refreshed
- Invalidate();
- foreach (var dc in this)
- {
- dc.Left += dx;
- dc.Top += dy;
- modified = true;
- }
-
- // Invalidate after
- Invalidate();
-
- // If we moved something, tell the surface it's modified!
- if (modified)
- {
- Parent.Modified = true;
- }
- }
-
- ///
- /// Indicates whether on of the elements is clickable at the given location
- ///
- /// x coordinate to be checked
- /// y coordinate to be checked
- /// true if one of the elements in the list is clickable at the given location, false otherwise
- public bool ClickableAt(int x, int y)
- {
- bool ret = false;
- foreach (var dc in this)
- {
- ret |= dc.ClickableAt(x, y);
- }
-
- return ret;
- }
-
- ///
- /// retrieves the topmost element being clickable at the given location
- ///
- /// x coordinate to be checked
- /// y coordinate to be checked
- /// the topmost element from the list being clickable at the given location, null if there is no clickable element
- public IDrawableContainer ClickableElementAt(int x, int y)
- {
- for (int i = Count - 1; i >= 0; i--)
- {
- if (this[i].ClickableAt(x, y))
- {
- return this[i];
- }
- }
-
- return null;
- }
-
- ///
- /// Dispatches OnDoubleClick to all elements in the list.
- ///
- public void OnDoubleClick()
- {
- foreach (var drawableContainer in this)
- {
- var dc = (DrawableContainer) drawableContainer;
- dc.OnDoubleClick();
- }
- }
-
- ///
- /// Check if there are any intersecting filters, if so we need to redraw more
- ///
- ///
- /// true if an filter intersects
- public bool HasIntersectingFilters(Rectangle clipRectangle)
- {
- foreach (var dc in this)
- {
- if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE)
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
- /// Check if any of the drawableContainers are inside the rectangle
- ///
- ///
- ///
- public bool IntersectsWith(Rectangle clipRectangle)
- {
- foreach (var dc in this)
- {
- if (dc.DrawingBounds.IntersectsWith(clipRectangle))
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
- /// A rectangle containing DrawingBounds of all drawableContainers in this list,
- /// or empty rectangle if nothing is there.
- ///
- 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;
- }
- }
- }
-
- ///
- /// Triggers all elements in the list ot be redrawn.
- ///
- /// the to the bitmap related Graphics object
- /// Bitmap to draw
- /// the rendermode in which the element is to be drawn
- ///
- public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle)
- {
- if (Parent == null)
- {
- return;
- }
-
- foreach (var drawableContainer in this)
- {
- var dc = (DrawableContainer) drawableContainer;
- if (dc.Parent == null)
- {
- continue;
- }
-
- if (dc.DrawingBounds.IntersectsWith(clipRectangle))
- {
- dc.DrawContent(g, bitmap, renderMode, clipRectangle);
- }
- }
- }
-
- ///
- /// Pass the field changed event to all elements in the list
- ///
- ///
- ///
- public void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e)
- {
- foreach (var drawableContainer in this)
- {
- var dc = (DrawableContainer) drawableContainer;
- dc.HandleFieldChanged(sender, e);
- }
- }
-
- ///
- /// Invalidate the bounds of all the DC's in this list
- ///
- public void Invalidate()
- {
- if (Parent == null)
- {
- return;
- }
-
- Rectangle region = Rectangle.Empty;
- foreach (var dc in this)
- {
- region = Rectangle.Union(region, dc.DrawingBounds);
- }
-
- Parent.InvalidateElements(region);
- }
-
- ///
- /// Indicates whether the given list of elements can be pulled up,
- /// i.e. whether there is at least one unselected element higher in hierarchy
- ///
- /// list of elements to pull up
- /// true if the elements could be pulled up
- public bool CanPullUp(IDrawableContainerList elements)
- {
- if (elements.Count == 0 || elements.Count == Count)
- {
- return false;
- }
-
- foreach (var element in elements)
- {
- if (IndexOf(element) < Count - elements.Count)
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
- /// Pulls one or several elements up one level in hierarchy (z-index).
- ///
- /// list of elements to pull up
- public void PullElementsUp(IDrawableContainerList elements)
- {
- for (int i = Count - 1; i >= 0; i--)
- {
- var dc = this[i];
- if (!elements.Contains(dc))
- {
- continue;
- }
-
- if (Count > i + 1 && !elements.Contains(this[i + 1]))
- {
- SwapElements(i, i + 1);
- }
- }
- }
-
- ///
- /// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index).
- ///
- /// of elements to pull to top
- public void PullElementsToTop(IDrawableContainerList elements)
- {
- var dcs = ToArray();
- foreach (var dc in dcs)
- {
- if (!elements.Contains(dc))
- {
- continue;
- }
-
- Remove(dc);
- Add(dc);
- Parent.Modified = true;
- }
- }
-
- ///
- /// Indicates whether the given list of elements can be pushed down,
- /// i.e. whether there is at least one unselected element lower in hierarchy
- ///
- /// list of elements to push down
- /// true if the elements could be pushed down
- public bool CanPushDown(IDrawableContainerList elements)
- {
- if (elements.Count == 0 || elements.Count == Count)
- {
- return false;
- }
-
- foreach (var element in elements)
- {
- if (IndexOf(element) >= elements.Count)
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
- /// Pushes one or several elements down one level in hierarchy (z-index).
- ///
- /// list of elements to push down
- public void PushElementsDown(IDrawableContainerList elements)
- {
- for (int i = 0; i < Count; i++)
- {
- var dc = this[i];
- if (!elements.Contains(dc))
- {
- continue;
- }
-
- if ((i > 0) && !elements.Contains(this[i - 1]))
- {
- SwapElements(i, i - 1);
- }
- }
- }
-
- ///
- /// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index).
- ///
- /// of elements to push to bottom
- public void PushElementsToBottom(IDrawableContainerList elements)
- {
- var dcs = ToArray();
- for (int i = dcs.Length - 1; i >= 0; i--)
- {
- var dc = dcs[i];
- if (!elements.Contains(dc))
- {
- continue;
- }
-
- Remove(dc);
- Insert(0, dc);
- Parent.Modified = true;
- }
- }
-
- ///
- /// swaps two elements in hierarchy (z-index),
- /// checks both indices to be in range
- ///
- /// index of the 1st element
- /// index of the 2nd element
- private void SwapElements(int index1, int index2)
- {
- if (index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || index1 == index2)
- {
- return;
- }
-
- var dc = this[index1];
- this[index1] = this[index2];
- this[index2] = dc;
- Parent.Modified = true;
- }
-
- ///
- /// Add items to a context menu for the selected item
- ///
- ///
- ///
- public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface)
- {
- bool push = surface.Elements.CanPushDown(this);
- bool pull = surface.Elements.CanPullUp(this);
-
- ToolStripMenuItem item;
-
- // Pull "up"
- if (pull)
- {
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uptotop));
- item.Click += delegate
- {
- surface.Elements.PullElementsToTop(this);
- surface.Elements.Invalidate();
- };
- menu.Items.Add(item);
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uponelevel));
- item.Click += delegate
- {
- surface.Elements.PullElementsUp(this);
- surface.Elements.Invalidate();
- };
- menu.Items.Add(item);
- }
-
- // Push "down"
- if (push)
- {
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downtobottom));
- item.Click += delegate
- {
- surface.Elements.PushElementsToBottom(this);
- surface.Elements.Invalidate();
- };
- menu.Items.Add(item);
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downonelevel));
- item.Click += delegate
- {
- surface.Elements.PushElementsDown(this);
- surface.Elements.Invalidate();
- };
- menu.Items.Add(item);
- }
-
- // Duplicate
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate));
- item.Click += delegate
- {
- IDrawableContainerList dcs = this.Clone();
- dcs.Parent = surface;
- dcs.MoveBy(10, 10);
- surface.AddElements(dcs);
- surface.DeselectAllElements();
- surface.SelectElements(dcs);
- };
- menu.Items.Add(item);
-
- // Copy
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard))
- {
- Image = (Image) EditorFormResources.GetObject("copyToolStripMenuItem.Image")
- };
- item.Click += delegate { ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); };
- menu.Items.Add(item);
-
- // Cut
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard))
- {
- Image = (Image) EditorFormResources.GetObject("btnCut.Image")
- };
- item.Click += delegate
- {
- ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this);
- surface.RemoveElements(this);
- };
- menu.Items.Add(item);
-
- // Delete
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement))
- {
- Image = (Image) EditorFormResources.GetObject("removeObjectToolStripMenuItem.Image")
- };
- item.Click += delegate { surface.RemoveElements(this); };
- menu.Items.Add(item);
-
- // Reset
- bool canReset = false;
- foreach (var drawableContainer in this)
- {
- var container = (DrawableContainer) drawableContainer;
- if (container.HasDefaultSize)
- {
- canReset = true;
- }
- }
-
- if (canReset)
- {
- item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize));
- //item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image")));
- item.Click += delegate
- {
- MakeBoundsChangeUndoable(false);
- foreach (var drawableContainer in this)
- {
- var container = (DrawableContainer) drawableContainer;
- if (!container.HasDefaultSize)
- {
- continue;
- }
-
- Size defaultSize = container.DefaultSize;
- container.MakeBoundsChangeUndoable(false);
- container.Width = defaultSize.Width;
- container.Height = defaultSize.Height;
- }
-
- surface.Invalidate();
- };
- menu.Items.Add(item);
- }
- }
-
- public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface)
- {
- if (!(iSurface is Surface surface))
- {
- return;
- }
-
- bool hasMenu = false;
- foreach (var drawableContainer in this)
- {
- var container = (DrawableContainer) drawableContainer;
- if (!container.HasContextMenu)
- {
- continue;
- }
-
- hasMenu = true;
- break;
- }
-
- if (hasMenu)
- {
- ContextMenuStrip menu = new ContextMenuStrip();
- AddContextMenuItems(menu, surface);
- if (menu.Items.Count > 0)
- {
- menu.Show(surface, surface.ToSurfaceCoordinates(e.Location));
- while (true)
- {
- if (menu.Visible)
- {
- Application.DoEvents();
- Thread.Sleep(100);
- }
- else
- {
- menu.Dispose();
- break;
- }
- }
- }
- }
- }
-
- private bool _disposedValue; // To detect redundant calls
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
- {
- foreach (var drawableContainer in this)
- {
- drawableContainer.Dispose();
- }
- }
-
- _disposedValue = true;
- }
- }
-
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- }
-
- ///
- /// Adjust UI elements to the supplied DPI settings
- ///
- ///
- public void AdjustToDpi(uint dpi)
- {
- foreach (var drawableContainer in this)
- {
- drawableContainer.AdjustToDpi(dpi);
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Threading;
+using System.Windows.Forms;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Configuration;
+using Greenshot.Editor.Forms;
+using Greenshot.Editor.Memento;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers.
+ ///
+ [Serializable]
+ public class DrawableContainerList : List, IDrawableContainerList
+ {
+ private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm));
+
+ public Guid ParentID { get; private set; }
+
+ public DrawableContainerList()
+ {
+ }
+
+ public DrawableContainerList(Guid parentId)
+ {
+ ParentID = parentId;
+ }
+
+ public EditStatus Status
+ {
+ get { return this[Count - 1].Status; }
+ set
+ {
+ foreach (var dc in this)
+ {
+ dc.Status = value;
+ }
+ }
+ }
+
+ public List AsIDrawableContainerList()
+ {
+ List interfaceList = new List();
+ foreach (IDrawableContainer container in this)
+ {
+ interfaceList.Add(container);
+ }
+
+ return interfaceList;
+ }
+
+ ///
+ /// Gets or sets the selection status of the elements.
+ /// If several elements are in the list, true is only returned when all elements are selected.
+ ///
+ public bool Selected
+ {
+ get
+ {
+ bool ret = true;
+ foreach (var dc in this)
+ {
+ ret &= dc.Selected;
+ }
+
+ return ret;
+ }
+ set
+ {
+ foreach (var dc in this)
+ {
+ dc.Selected = value;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the parent control of the elements in the list.
+ /// If there are several elements, the parent control of the last added is returned.
+ ///
+ public ISurface Parent
+ {
+ get
+ {
+ if (Count > 0)
+ {
+ return this[Count - 1].Parent;
+ }
+
+ return null;
+ }
+ set
+ {
+ ParentID = value?.ID ?? Guid.NewGuid();
+ foreach (var drawableContainer in this)
+ {
+ var dc = (DrawableContainer) drawableContainer;
+ dc.Parent = value;
+ }
+ }
+ }
+
+ ///
+ /// Make a following bounds change on this containerlist undoable!
+ ///
+ /// true means allow the moves to be merged
+ public void MakeBoundsChangeUndoable(bool allowMerge)
+ {
+ if (Count > 0 && Parent != null)
+ {
+ var clone = new DrawableContainerList();
+ clone.AddRange(this);
+ Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge);
+ }
+ }
+
+ ///
+ /// Apply matrix to all elements
+ ///
+ public void Transform(Matrix matrix)
+ {
+ // Track modifications
+ bool modified = false;
+ Invalidate();
+ foreach (var dc in this)
+ {
+ dc.Transform(matrix);
+ modified = true;
+ }
+
+ // Invalidate after
+ Invalidate();
+ // If we moved something, tell the surface it's modified!
+ if (modified)
+ {
+ Parent.Modified = true;
+ }
+ }
+
+ ///
+ /// Moves all elements in the list by the given amount of pixels.
+ ///
+ /// pixels to move horizontally
+ /// pixels to move vertically
+ public void MoveBy(int dx, int dy)
+ {
+ // Track modifications
+ bool modified = false;
+
+ // Invalidate before moving, otherwise the old locations aren't refreshed
+ Invalidate();
+ foreach (var dc in this)
+ {
+ dc.Left += dx;
+ dc.Top += dy;
+ modified = true;
+ }
+
+ // Invalidate after
+ Invalidate();
+
+ // If we moved something, tell the surface it's modified!
+ if (modified)
+ {
+ Parent.Modified = true;
+ }
+ }
+
+ ///
+ /// Indicates whether on of the elements is clickable at the given location
+ ///
+ /// x coordinate to be checked
+ /// y coordinate to be checked
+ /// true if one of the elements in the list is clickable at the given location, false otherwise
+ public bool ClickableAt(int x, int y)
+ {
+ bool ret = false;
+ foreach (var dc in this)
+ {
+ ret |= dc.ClickableAt(x, y);
+ }
+
+ return ret;
+ }
+
+ ///
+ /// retrieves the topmost element being clickable at the given location
+ ///
+ /// x coordinate to be checked
+ /// y coordinate to be checked
+ /// the topmost element from the list being clickable at the given location, null if there is no clickable element
+ public IDrawableContainer ClickableElementAt(int x, int y)
+ {
+ for (int i = Count - 1; i >= 0; i--)
+ {
+ if (this[i].ClickableAt(x, y))
+ {
+ return this[i];
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Dispatches OnDoubleClick to all elements in the list.
+ ///
+ public void OnDoubleClick()
+ {
+ foreach (var drawableContainer in this)
+ {
+ var dc = (DrawableContainer) drawableContainer;
+ dc.OnDoubleClick();
+ }
+ }
+
+ ///
+ /// Check if there are any intersecting filters, if so we need to redraw more
+ ///
+ ///
+ /// true if an filter intersects
+ public bool HasIntersectingFilters(Rectangle clipRectangle)
+ {
+ foreach (var dc in this)
+ {
+ if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Check if any of the drawableContainers are inside the rectangle
+ ///
+ ///
+ ///
+ public bool IntersectsWith(Rectangle clipRectangle)
+ {
+ foreach (var dc in this)
+ {
+ if (dc.DrawingBounds.IntersectsWith(clipRectangle))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// A rectangle containing DrawingBounds of all drawableContainers in this list,
+ /// or empty rectangle if nothing is there.
+ ///
+ 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;
+ }
+ }
+ }
+
+ ///
+ /// Triggers all elements in the list ot be redrawn.
+ ///
+ /// the to the bitmap related Graphics object
+ /// Bitmap to draw
+ /// the rendermode in which the element is to be drawn
+ ///
+ public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle)
+ {
+ if (Parent == null)
+ {
+ return;
+ }
+
+ foreach (var drawableContainer in this)
+ {
+ var dc = (DrawableContainer) drawableContainer;
+ if (dc.Parent == null)
+ {
+ continue;
+ }
+
+ if (dc.DrawingBounds.IntersectsWith(clipRectangle))
+ {
+ dc.DrawContent(g, bitmap, renderMode, clipRectangle);
+ }
+ }
+ }
+
+ ///
+ /// Pass the field changed event to all elements in the list
+ ///
+ ///
+ ///
+ public void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e)
+ {
+ foreach (var drawableContainer in this)
+ {
+ var dc = (DrawableContainer) drawableContainer;
+ dc.HandleFieldChanged(sender, e);
+ }
+ }
+
+ ///
+ /// Invalidate the bounds of all the DC's in this list
+ ///
+ public void Invalidate()
+ {
+ if (Parent == null)
+ {
+ return;
+ }
+
+ Rectangle region = Rectangle.Empty;
+ foreach (var dc in this)
+ {
+ region = Rectangle.Union(region, dc.DrawingBounds);
+ }
+
+ Parent.InvalidateElements(region);
+ }
+
+ ///
+ /// Indicates whether the given list of elements can be pulled up,
+ /// i.e. whether there is at least one unselected element higher in hierarchy
+ ///
+ /// list of elements to pull up
+ /// true if the elements could be pulled up
+ public bool CanPullUp(IDrawableContainerList elements)
+ {
+ if (elements.Count == 0 || elements.Count == Count)
+ {
+ return false;
+ }
+
+ foreach (var element in elements)
+ {
+ if (IndexOf(element) < Count - elements.Count)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Pulls one or several elements up one level in hierarchy (z-index).
+ ///
+ /// list of elements to pull up
+ public void PullElementsUp(IDrawableContainerList elements)
+ {
+ for (int i = Count - 1; i >= 0; i--)
+ {
+ var dc = this[i];
+ if (!elements.Contains(dc))
+ {
+ continue;
+ }
+
+ if (Count > i + 1 && !elements.Contains(this[i + 1]))
+ {
+ SwapElements(i, i + 1);
+ }
+ }
+ }
+
+ ///
+ /// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index).
+ ///
+ /// of elements to pull to top
+ public void PullElementsToTop(IDrawableContainerList elements)
+ {
+ var dcs = ToArray();
+ foreach (var dc in dcs)
+ {
+ if (!elements.Contains(dc))
+ {
+ continue;
+ }
+
+ Remove(dc);
+ Add(dc);
+ Parent.Modified = true;
+ }
+ }
+
+ ///
+ /// Indicates whether the given list of elements can be pushed down,
+ /// i.e. whether there is at least one unselected element lower in hierarchy
+ ///
+ /// list of elements to push down
+ /// true if the elements could be pushed down
+ public bool CanPushDown(IDrawableContainerList elements)
+ {
+ if (elements.Count == 0 || elements.Count == Count)
+ {
+ return false;
+ }
+
+ foreach (var element in elements)
+ {
+ if (IndexOf(element) >= elements.Count)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Pushes one or several elements down one level in hierarchy (z-index).
+ ///
+ /// list of elements to push down
+ public void PushElementsDown(IDrawableContainerList elements)
+ {
+ for (int i = 0; i < Count; i++)
+ {
+ var dc = this[i];
+ if (!elements.Contains(dc))
+ {
+ continue;
+ }
+
+ if ((i > 0) && !elements.Contains(this[i - 1]))
+ {
+ SwapElements(i, i - 1);
+ }
+ }
+ }
+
+ ///
+ /// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index).
+ ///
+ /// of elements to push to bottom
+ public void PushElementsToBottom(IDrawableContainerList elements)
+ {
+ var dcs = ToArray();
+ for (int i = dcs.Length - 1; i >= 0; i--)
+ {
+ var dc = dcs[i];
+ if (!elements.Contains(dc))
+ {
+ continue;
+ }
+
+ Remove(dc);
+ Insert(0, dc);
+ Parent.Modified = true;
+ }
+ }
+
+ ///
+ /// swaps two elements in hierarchy (z-index),
+ /// checks both indices to be in range
+ ///
+ /// index of the 1st element
+ /// index of the 2nd element
+ private void SwapElements(int index1, int index2)
+ {
+ if (index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || index1 == index2)
+ {
+ return;
+ }
+
+ var dc = this[index1];
+ this[index1] = this[index2];
+ this[index2] = dc;
+ Parent.Modified = true;
+ }
+
+ ///
+ /// Add items to a context menu for the selected item
+ ///
+ ///
+ ///
+ public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface)
+ {
+ bool push = surface.Elements.CanPushDown(this);
+ bool pull = surface.Elements.CanPullUp(this);
+
+ ToolStripMenuItem item;
+
+ // Pull "up"
+ if (pull)
+ {
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uptotop));
+ item.Click += delegate
+ {
+ surface.Elements.PullElementsToTop(this);
+ surface.Elements.Invalidate();
+ };
+ menu.Items.Add(item);
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uponelevel));
+ item.Click += delegate
+ {
+ surface.Elements.PullElementsUp(this);
+ surface.Elements.Invalidate();
+ };
+ menu.Items.Add(item);
+ }
+
+ // Push "down"
+ if (push)
+ {
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downtobottom));
+ item.Click += delegate
+ {
+ surface.Elements.PushElementsToBottom(this);
+ surface.Elements.Invalidate();
+ };
+ menu.Items.Add(item);
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downonelevel));
+ item.Click += delegate
+ {
+ surface.Elements.PushElementsDown(this);
+ surface.Elements.Invalidate();
+ };
+ menu.Items.Add(item);
+ }
+
+ // Duplicate
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate));
+ item.Click += delegate
+ {
+ IDrawableContainerList dcs = this.Clone();
+ dcs.Parent = surface;
+ dcs.MoveBy(10, 10);
+ surface.AddElements(dcs);
+ surface.DeselectAllElements();
+ surface.SelectElements(dcs);
+ };
+ menu.Items.Add(item);
+
+ // Copy
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard))
+ {
+ Image = (Image) EditorFormResources.GetObject("copyToolStripMenuItem.Image")
+ };
+ item.Click += delegate { ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); };
+ menu.Items.Add(item);
+
+ // Cut
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard))
+ {
+ Image = (Image) EditorFormResources.GetObject("btnCut.Image")
+ };
+ item.Click += delegate
+ {
+ ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this);
+ surface.RemoveElements(this);
+ };
+ menu.Items.Add(item);
+
+ // Delete
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement))
+ {
+ Image = (Image) EditorFormResources.GetObject("removeObjectToolStripMenuItem.Image")
+ };
+ item.Click += delegate { surface.RemoveElements(this); };
+ menu.Items.Add(item);
+
+ // Reset
+ bool canReset = false;
+ foreach (var drawableContainer in this)
+ {
+ var container = (DrawableContainer) drawableContainer;
+ if (container.HasDefaultSize)
+ {
+ canReset = true;
+ }
+ }
+
+ if (canReset)
+ {
+ item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize));
+ //item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image")));
+ item.Click += delegate
+ {
+ MakeBoundsChangeUndoable(false);
+ foreach (var drawableContainer in this)
+ {
+ var container = (DrawableContainer) drawableContainer;
+ if (!container.HasDefaultSize)
+ {
+ continue;
+ }
+
+ Size defaultSize = container.DefaultSize;
+ container.MakeBoundsChangeUndoable(false);
+ container.Width = defaultSize.Width;
+ container.Height = defaultSize.Height;
+ }
+
+ surface.Invalidate();
+ };
+ menu.Items.Add(item);
+ }
+ }
+
+ public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface)
+ {
+ if (!(iSurface is Surface surface))
+ {
+ return;
+ }
+
+ bool hasMenu = false;
+ foreach (var drawableContainer in this)
+ {
+ var container = (DrawableContainer) drawableContainer;
+ if (!container.HasContextMenu)
+ {
+ continue;
+ }
+
+ hasMenu = true;
+ break;
+ }
+
+ if (hasMenu)
+ {
+ ContextMenuStrip menu = new ContextMenuStrip();
+ AddContextMenuItems(menu, surface);
+ if (menu.Items.Count > 0)
+ {
+ menu.Show(surface, surface.ToSurfaceCoordinates(e.Location));
+ while (true)
+ {
+ if (menu.Visible)
+ {
+ Application.DoEvents();
+ Thread.Sleep(100);
+ }
+ else
+ {
+ menu.Dispose();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private bool _disposedValue; // To detect redundant calls
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ foreach (var drawableContainer in this)
+ {
+ drawableContainer.Dispose();
+ }
+ }
+
+ _disposedValue = true;
+ }
+ }
+
+ // This code added to correctly implement the disposable pattern.
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
+ Dispose(true);
+ }
+
+ ///
+ /// Adjust UI elements to the supplied DPI settings
+ ///
+ ///
+ public void AdjustToDpi(uint dpi)
+ {
+ foreach (var drawableContainer in this)
+ {
+ drawableContainer.AdjustToDpi(dpi);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/EllipseContainer.cs b/src/Greenshot.Editor/Drawing/EllipseContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/EllipseContainer.cs
rename to src/Greenshot.Editor/Drawing/EllipseContainer.cs
index 822587901..d2c854cb1 100644
--- a/src/Greenshot/Drawing/EllipseContainer.cs
+++ b/src/Greenshot.Editor/Drawing/EllipseContainer.cs
@@ -1,163 +1,163 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of EllipseContainer.
- ///
- [Serializable()]
- public class EllipseContainer : DrawableContainer
- {
- public EllipseContainer(Surface parent) : base(parent)
- {
- CreateDefaultAdorners();
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 2);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
- AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
- AddField(GetType(), FieldType.SHADOW, true);
- }
-
- public override void Draw(Graphics graphics, RenderMode renderMode)
- {
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
-
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow);
- }
-
- ///
- /// This allows another container to draw an ellipse
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow)
- {
- bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
- // draw shadow before anything else
- if (shadow && (lineVisible || Colors.IsVisible(fillColor)))
- {
- int basealpha = 100;
- int alpha = basealpha;
- int steps = 5;
- int currentStep = lineVisible ? 1 : 0;
- while (currentStep <= steps)
- {
- using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))
- {
- Width = lineVisible ? lineThickness : 1
- };
- Rectangle shadowRect = GuiRectangle.GetGuiRectangle(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height);
- graphics.DrawEllipse(shadowPen, shadowRect);
- currentStep++;
- alpha -= basealpha / steps;
- }
- }
-
- //draw the original shape
- if (Colors.IsVisible(fillColor))
- {
- using Brush brush = new SolidBrush(fillColor);
- graphics.FillEllipse(brush, rect);
- }
-
- if (lineVisible)
- {
- using Pen pen = new Pen(lineColor, lineThickness);
- graphics.DrawEllipse(pen, rect);
- }
- }
-
- public override bool Contains(int x, int y)
- {
- return EllipseContains(this, x, y);
- }
-
- ///
- /// Allow the code to be used externally
- ///
- ///
- ///
- ///
- ///
- public static bool EllipseContains(DrawableContainer caller, int x, int y)
- {
- double xDistanceFromCenter = x - (caller.Left + caller.Width / 2);
- double yDistanceFromCenter = y - (caller.Top + caller.Height / 2);
- // ellipse: x^2/a^2 + y^2/b^2 = 1
- return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1;
- }
-
- public override bool ClickableAt(int x, int y)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- return EllipseClickableAt(rect, lineThickness, fillColor, x, y);
- }
-
- public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y)
- {
- // If we clicked inside the rectangle and it's visible we are clickable at.
- if (!Color.Transparent.Equals(fillColor))
- {
- if (rect.Contains(x, y))
- {
- return true;
- }
- }
-
- // check the rest of the lines
- if (lineThickness > 0)
- {
- using Pen pen = new Pen(Color.White, lineThickness);
- using GraphicsPath path = new GraphicsPath();
- path.AddEllipse(rect);
- return path.IsOutlineVisible(x, y, pen);
- }
-
- return false;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of EllipseContainer.
+ ///
+ [Serializable()]
+ public class EllipseContainer : DrawableContainer
+ {
+ public EllipseContainer(Surface parent) : base(parent)
+ {
+ CreateDefaultAdorners();
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 2);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
+ AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
+ AddField(GetType(), FieldType.SHADOW, true);
+ }
+
+ public override void Draw(Graphics graphics, RenderMode renderMode)
+ {
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow);
+ }
+
+ ///
+ /// This allows another container to draw an ellipse
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow)
+ {
+ bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
+ // draw shadow before anything else
+ if (shadow && (lineVisible || Colors.IsVisible(fillColor)))
+ {
+ int basealpha = 100;
+ int alpha = basealpha;
+ int steps = 5;
+ int currentStep = lineVisible ? 1 : 0;
+ while (currentStep <= steps)
+ {
+ using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))
+ {
+ Width = lineVisible ? lineThickness : 1
+ };
+ Rectangle shadowRect = GuiRectangle.GetGuiRectangle(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height);
+ graphics.DrawEllipse(shadowPen, shadowRect);
+ currentStep++;
+ alpha -= basealpha / steps;
+ }
+ }
+
+ //draw the original shape
+ if (Colors.IsVisible(fillColor))
+ {
+ using Brush brush = new SolidBrush(fillColor);
+ graphics.FillEllipse(brush, rect);
+ }
+
+ if (lineVisible)
+ {
+ using Pen pen = new Pen(lineColor, lineThickness);
+ graphics.DrawEllipse(pen, rect);
+ }
+ }
+
+ public override bool Contains(int x, int y)
+ {
+ return EllipseContains(this, x, y);
+ }
+
+ ///
+ /// Allow the code to be used externally
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool EllipseContains(DrawableContainer caller, int x, int y)
+ {
+ double xDistanceFromCenter = x - (caller.Left + caller.Width / 2);
+ double yDistanceFromCenter = y - (caller.Top + caller.Height / 2);
+ // ellipse: x^2/a^2 + y^2/b^2 = 1
+ return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1;
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ return EllipseClickableAt(rect, lineThickness, fillColor, x, y);
+ }
+
+ public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y)
+ {
+ // If we clicked inside the rectangle and it's visible we are clickable at.
+ if (!Color.Transparent.Equals(fillColor))
+ {
+ if (rect.Contains(x, y))
+ {
+ return true;
+ }
+ }
+
+ // check the rest of the lines
+ if (lineThickness > 0)
+ {
+ using Pen pen = new Pen(Color.White, lineThickness);
+ using GraphicsPath path = new GraphicsPath();
+ path.AddEllipse(rect);
+ return path.IsOutlineVisible(x, y, pen);
+ }
+
+ return false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/src/Greenshot.Editor/Drawing/Fields/AbstractFieldHolder.cs
similarity index 96%
rename from src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs
rename to src/Greenshot.Editor/Drawing/Fields/AbstractFieldHolder.cs
index 0ca381ace..a3f3c92da 100644
--- a/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/AbstractFieldHolder.cs
@@ -1,192 +1,192 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Runtime.Serialization;
-using Greenshot.Base.IniFile;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Configuration;
-using log4net;
-
-namespace Greenshot.Drawing.Fields
-{
- ///
- /// Basic IFieldHolder implementation, providing access to a set of fields
- ///
- [Serializable]
- public abstract class AbstractFieldHolder : IFieldHolder
- {
- private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder));
- private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection();
- [NonSerialized] private readonly IDictionary _handlers = new Dictionary();
-
- ///
- /// called when a field's value has changed
- ///
- [NonSerialized] private FieldChangedEventHandler _fieldChanged;
-
- public event FieldChangedEventHandler FieldChanged
- {
- add { _fieldChanged += value; }
- remove { _fieldChanged -= value; }
- }
-
- // we keep two Collections of our fields, dictionary for quick access, list for serialization
- // this allows us to use default serialization
- [NonSerialized] private IDictionary _fieldsByType = new Dictionary();
- private readonly IList fields = new List();
-
- [OnDeserialized]
- private void OnDeserialized(StreamingContext context)
- {
- _fieldsByType = new Dictionary();
- // listen to changing properties
- foreach (var field in fields)
- {
- field.PropertyChanged += delegate { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); };
- _fieldsByType[field.FieldType] = field;
- }
- }
-
- public void AddField(Type requestingType, IFieldType fieldType, object fieldValue)
- {
- AddField(EditorConfig.CreateField(requestingType, fieldType, fieldValue));
- }
-
- public virtual void AddField(IField field)
- {
- fields.Add(field);
- if (_fieldsByType == null)
- {
- return;
- }
-
- if (_fieldsByType.ContainsKey(field.FieldType))
- {
- if (LOG.IsDebugEnabled)
- {
- LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType());
- }
- }
-
- _fieldsByType[field.FieldType] = field;
-
- _handlers[field] = (sender, args) => { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); };
- field.PropertyChanged += _handlers[field];
- }
-
- public void RemoveField(IField field)
- {
- fields.Remove(field);
- _fieldsByType.Remove(field.FieldType);
- field.PropertyChanged -= _handlers[field];
- _handlers.Remove(field);
- }
-
- public IList GetFields()
- {
- return fields;
- }
-
-
- public IField GetField(IFieldType fieldType)
- {
- try
- {
- return _fieldsByType[fieldType];
- }
- catch (KeyNotFoundException e)
- {
- throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e);
- }
- }
-
- public object GetFieldValue(IFieldType fieldType)
- {
- return GetField(fieldType)?.Value;
- }
-
- public string GetFieldValueAsString(IFieldType fieldType)
- {
- return Convert.ToString(GetFieldValue(fieldType));
- }
-
- public int GetFieldValueAsInt(IFieldType fieldType)
- {
- return Convert.ToInt32(GetFieldValue(fieldType));
- }
-
- public decimal GetFieldValueAsDecimal(IFieldType fieldType)
- {
- return Convert.ToDecimal(GetFieldValue(fieldType));
- }
-
- public double GetFieldValueAsDouble(IFieldType fieldType)
- {
- return Convert.ToDouble(GetFieldValue(fieldType));
- }
-
- public float GetFieldValueAsFloat(IFieldType fieldType)
- {
- return Convert.ToSingle(GetFieldValue(fieldType));
- }
-
- public bool GetFieldValueAsBool(IFieldType fieldType)
- {
- return Convert.ToBoolean(GetFieldValue(fieldType));
- }
-
- public Color GetFieldValueAsColor(IFieldType fieldType, Color defaultColor = default)
- {
- return (Color) (GetFieldValue(fieldType) ?? defaultColor);
- }
-
- public bool HasField(IFieldType fieldType)
- {
- return _fieldsByType.ContainsKey(fieldType);
- }
-
- public bool HasFieldValue(IFieldType fieldType)
- {
- return HasField(fieldType) && _fieldsByType[fieldType].HasValue;
- }
-
- public void SetFieldValue(IFieldType fieldType, object value)
- {
- try
- {
- _fieldsByType[fieldType].Value = value;
- }
- catch (KeyNotFoundException e)
- {
- throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e);
- }
- }
-
- protected void OnFieldChanged(object sender, FieldChangedEventArgs e)
- {
- _fieldChanged?.Invoke(sender, e);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Runtime.Serialization;
+using Greenshot.Base.IniFile;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Configuration;
+using log4net;
+
+namespace Greenshot.Editor.Drawing.Fields
+{
+ ///
+ /// Basic IFieldHolder implementation, providing access to a set of fields
+ ///
+ [Serializable]
+ public abstract class AbstractFieldHolder : IFieldHolder
+ {
+ private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder));
+ private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection();
+ [NonSerialized] private readonly IDictionary _handlers = new Dictionary();
+
+ ///
+ /// called when a field's value has changed
+ ///
+ [NonSerialized] private FieldChangedEventHandler _fieldChanged;
+
+ public event FieldChangedEventHandler FieldChanged
+ {
+ add { _fieldChanged += value; }
+ remove { _fieldChanged -= value; }
+ }
+
+ // we keep two Collections of our fields, dictionary for quick access, list for serialization
+ // this allows us to use default serialization
+ [NonSerialized] private IDictionary _fieldsByType = new Dictionary();
+ private readonly IList fields = new List();
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext context)
+ {
+ _fieldsByType = new Dictionary();
+ // listen to changing properties
+ foreach (var field in fields)
+ {
+ field.PropertyChanged += delegate { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); };
+ _fieldsByType[field.FieldType] = field;
+ }
+ }
+
+ public void AddField(Type requestingType, IFieldType fieldType, object fieldValue)
+ {
+ AddField(EditorConfig.CreateField(requestingType, fieldType, fieldValue));
+ }
+
+ public virtual void AddField(IField field)
+ {
+ fields.Add(field);
+ if (_fieldsByType == null)
+ {
+ return;
+ }
+
+ if (_fieldsByType.ContainsKey(field.FieldType))
+ {
+ if (LOG.IsDebugEnabled)
+ {
+ LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType());
+ }
+ }
+
+ _fieldsByType[field.FieldType] = field;
+
+ _handlers[field] = (sender, args) => { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); };
+ field.PropertyChanged += _handlers[field];
+ }
+
+ public void RemoveField(IField field)
+ {
+ fields.Remove(field);
+ _fieldsByType.Remove(field.FieldType);
+ field.PropertyChanged -= _handlers[field];
+ _handlers.Remove(field);
+ }
+
+ public IList GetFields()
+ {
+ return fields;
+ }
+
+
+ public IField GetField(IFieldType fieldType)
+ {
+ try
+ {
+ return _fieldsByType[fieldType];
+ }
+ catch (KeyNotFoundException e)
+ {
+ throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e);
+ }
+ }
+
+ public object GetFieldValue(IFieldType fieldType)
+ {
+ return GetField(fieldType)?.Value;
+ }
+
+ public string GetFieldValueAsString(IFieldType fieldType)
+ {
+ return Convert.ToString(GetFieldValue(fieldType));
+ }
+
+ public int GetFieldValueAsInt(IFieldType fieldType)
+ {
+ return Convert.ToInt32(GetFieldValue(fieldType));
+ }
+
+ public decimal GetFieldValueAsDecimal(IFieldType fieldType)
+ {
+ return Convert.ToDecimal(GetFieldValue(fieldType));
+ }
+
+ public double GetFieldValueAsDouble(IFieldType fieldType)
+ {
+ return Convert.ToDouble(GetFieldValue(fieldType));
+ }
+
+ public float GetFieldValueAsFloat(IFieldType fieldType)
+ {
+ return Convert.ToSingle(GetFieldValue(fieldType));
+ }
+
+ public bool GetFieldValueAsBool(IFieldType fieldType)
+ {
+ return Convert.ToBoolean(GetFieldValue(fieldType));
+ }
+
+ public Color GetFieldValueAsColor(IFieldType fieldType, Color defaultColor = default)
+ {
+ return (Color) (GetFieldValue(fieldType) ?? defaultColor);
+ }
+
+ public bool HasField(IFieldType fieldType)
+ {
+ return _fieldsByType.ContainsKey(fieldType);
+ }
+
+ public bool HasFieldValue(IFieldType fieldType)
+ {
+ return HasField(fieldType) && _fieldsByType[fieldType].HasValue;
+ }
+
+ public void SetFieldValue(IFieldType fieldType, object value)
+ {
+ try
+ {
+ _fieldsByType[fieldType].Value = value;
+ }
+ catch (KeyNotFoundException e)
+ {
+ throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e);
+ }
+ }
+
+ protected void OnFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ _fieldChanged?.Invoke(sender, e);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/src/Greenshot.Editor/Drawing/Fields/AbstractFieldHolderWithChildren.cs
similarity index 96%
rename from src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs
rename to src/Greenshot.Editor/Drawing/Fields/AbstractFieldHolderWithChildren.cs
index bd680d992..968edef46 100644
--- a/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/AbstractFieldHolderWithChildren.cs
@@ -1,149 +1,149 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Fields
-{
- ///
- /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder,
- /// but has a List of IFieldHolder for children.
- /// Field values are passed to and from children as well.
- ///
- [Serializable]
- public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder
- {
- [NonSerialized] private readonly FieldChangedEventHandler _fieldChangedEventHandler;
-
- [NonSerialized] private EventHandler childrenChanged;
-
- public event EventHandler ChildrenChanged
- {
- add { childrenChanged += value; }
- remove { childrenChanged -= value; }
- }
-
- public IList Children = new List();
-
- public AbstractFieldHolderWithChildren()
- {
- _fieldChangedEventHandler = OnFieldChanged;
- }
-
- [OnDeserialized()]
- private void OnDeserialized(StreamingContext context)
- {
- // listen to changing properties
- foreach (IFieldHolder fieldHolder in Children)
- {
- fieldHolder.FieldChanged += _fieldChangedEventHandler;
- }
-
- childrenChanged?.Invoke(this, EventArgs.Empty);
- }
-
- public void AddChild(IFieldHolder fieldHolder)
- {
- Children.Add(fieldHolder);
- fieldHolder.FieldChanged += _fieldChangedEventHandler;
- childrenChanged?.Invoke(this, EventArgs.Empty);
- }
-
- public void RemoveChild(IFieldHolder fieldHolder)
- {
- Children.Remove(fieldHolder);
- fieldHolder.FieldChanged -= _fieldChangedEventHandler;
- childrenChanged?.Invoke(this, EventArgs.Empty);
- }
-
- public new IList GetFields()
- {
- var ret = new List();
- ret.AddRange(base.GetFields());
- foreach (IFieldHolder fh in Children)
- {
- ret.AddRange(fh.GetFields());
- }
-
- return ret;
- }
-
- public new IField GetField(IFieldType fieldType)
- {
- IField ret = null;
- if (base.HasField(fieldType))
- {
- ret = base.GetField(fieldType);
- }
- else
- {
- foreach (IFieldHolder fh in Children)
- {
- if (fh.HasField(fieldType))
- {
- ret = fh.GetField(fieldType);
- break;
- }
- }
- }
-
- if (ret == null)
- {
- throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType());
- }
-
- return ret;
- }
-
- public new bool HasField(IFieldType fieldType)
- {
- bool ret = base.HasField(fieldType);
- if (!ret)
- {
- foreach (IFieldHolder fh in Children)
- {
- if (fh.HasField(fieldType))
- {
- ret = true;
- break;
- }
- }
- }
-
- return ret;
- }
-
- public new bool HasFieldValue(IFieldType fieldType)
- {
- IField f = GetField(fieldType);
- return f != null && f.HasValue;
- }
-
- public new void SetFieldValue(IFieldType fieldType, object value)
- {
- IField f = GetField(fieldType);
- if (f != null) f.Value = value;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+
+namespace Greenshot.Editor.Drawing.Fields
+{
+ ///
+ /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder,
+ /// but has a List of IFieldHolder for children.
+ /// Field values are passed to and from children as well.
+ ///
+ [Serializable]
+ public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder
+ {
+ [NonSerialized] private readonly FieldChangedEventHandler _fieldChangedEventHandler;
+
+ [NonSerialized] private EventHandler childrenChanged;
+
+ public event EventHandler ChildrenChanged
+ {
+ add { childrenChanged += value; }
+ remove { childrenChanged -= value; }
+ }
+
+ public IList Children = new List();
+
+ public AbstractFieldHolderWithChildren()
+ {
+ _fieldChangedEventHandler = OnFieldChanged;
+ }
+
+ [OnDeserialized()]
+ private void OnDeserialized(StreamingContext context)
+ {
+ // listen to changing properties
+ foreach (IFieldHolder fieldHolder in Children)
+ {
+ fieldHolder.FieldChanged += _fieldChangedEventHandler;
+ }
+
+ childrenChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ public void AddChild(IFieldHolder fieldHolder)
+ {
+ Children.Add(fieldHolder);
+ fieldHolder.FieldChanged += _fieldChangedEventHandler;
+ childrenChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ public void RemoveChild(IFieldHolder fieldHolder)
+ {
+ Children.Remove(fieldHolder);
+ fieldHolder.FieldChanged -= _fieldChangedEventHandler;
+ childrenChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ public new IList GetFields()
+ {
+ var ret = new List();
+ ret.AddRange(base.GetFields());
+ foreach (IFieldHolder fh in Children)
+ {
+ ret.AddRange(fh.GetFields());
+ }
+
+ return ret;
+ }
+
+ public new IField GetField(IFieldType fieldType)
+ {
+ IField ret = null;
+ if (base.HasField(fieldType))
+ {
+ ret = base.GetField(fieldType);
+ }
+ else
+ {
+ foreach (IFieldHolder fh in Children)
+ {
+ if (fh.HasField(fieldType))
+ {
+ ret = fh.GetField(fieldType);
+ break;
+ }
+ }
+ }
+
+ if (ret == null)
+ {
+ throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType());
+ }
+
+ return ret;
+ }
+
+ public new bool HasField(IFieldType fieldType)
+ {
+ bool ret = base.HasField(fieldType);
+ if (!ret)
+ {
+ foreach (IFieldHolder fh in Children)
+ {
+ if (fh.HasField(fieldType))
+ {
+ ret = true;
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public new bool HasFieldValue(IFieldType fieldType)
+ {
+ IField f = GetField(fieldType);
+ return f != null && f.HasValue;
+ }
+
+ public new void SetFieldValue(IFieldType fieldType, object value)
+ {
+ IField f = GetField(fieldType);
+ if (f != null) f.Value = value;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/AbstractBindingConverter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/AbstractBindingConverter.cs
index b4e568986..0a993f766 100644
--- a/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/AbstractBindingConverter.cs
@@ -1,54 +1,54 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Basic IBindingConverter implementation
- ///
- public abstract class AbstractBindingConverter : IBindingConverter
- {
- public object convert(object o)
- {
- if (o == null)
- {
- return null;
- }
-
- if (o is T1)
- {
- return convert((T1) o);
- }
-
- if (o is T2)
- {
- return convert((T2) o);
- }
-
- throw new ArgumentException("Cannot handle argument of type " + o.GetType());
- }
-
- protected abstract T2 convert(T1 o);
- protected abstract T1 convert(T2 o);
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Basic IBindingConverter implementation
+ ///
+ public abstract class AbstractBindingConverter : IBindingConverter
+ {
+ public object convert(object o)
+ {
+ if (o == null)
+ {
+ return null;
+ }
+
+ if (o is T1)
+ {
+ return convert((T1) o);
+ }
+
+ if (o is T2)
+ {
+ return convert((T2) o);
+ }
+
+ throw new ArgumentException("Cannot handle argument of type " + o.GetType());
+ }
+
+ protected abstract T2 convert(T1 o);
+ protected abstract T1 convert(T2 o);
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/BidirectionalBinding.cs
similarity index 97%
rename from src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/BidirectionalBinding.cs
index 30cbbffa7..8dc390080 100644
--- a/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/BidirectionalBinding.cs
@@ -1,184 +1,184 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Reflection;
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Bidirectional binding of properties of two INotifyPropertyChanged instances.
- /// This implementation synchronizes null values, too. If you do not want this
- /// behavior (e.g. when binding to a
- ///
- public class BidirectionalBinding
- {
- private readonly INotifyPropertyChanged _controlObject;
- private readonly INotifyPropertyChanged _fieldObject;
- private readonly string _controlPropertyName;
- private readonly string _fieldPropertyName;
- private bool _updatingControl;
- private bool _updatingField;
- private IBindingConverter _converter;
- private readonly IBindingValidator _validator;
-
- ///
- /// Whether or not null values are passed on to the other object.
- ///
- protected bool AllowSynchronizeNull = true;
-
- ///
- /// Bind properties of two objects bidirectionally
- ///
- /// Object containing 1st property to bind
- /// Property of 1st object to bind
- /// Object containing 2nd property to bind
- /// Property of 2nd object to bind
- public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName)
- {
- _controlObject = controlObject;
- _fieldObject = fieldObject;
- _controlPropertyName = controlPropertyName;
- _fieldPropertyName = fieldPropertyName;
-
- _controlObject.PropertyChanged += ControlPropertyChanged;
- _fieldObject.PropertyChanged += FieldPropertyChanged;
- }
-
- ///
- /// Bind properties of two objects bidirectionally, converting the values using a converter
- ///
- /// Object containing 1st property to bind
- /// Property of 1st object to bind
- /// Object containing 2nd property to bind
- /// Property of 2nd object to bind
- /// taking care of converting the synchronized value to the correct target format and back
- public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName,
- IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName)
- {
- _converter = converter;
- }
-
- ///
- /// Bind properties of two objects bidirectionally, converting the values using a converter.
- /// Synchronization can be intercepted by adding a validator.
- ///
- /// Object containing 1st property to bind
- /// Property of 1st object to bind
- /// Object containing 2nd property to bind
- /// Property of 2nd object to bind
- /// validator to intercept synchronization if the value does not match certain criteria
- public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName,
- IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName)
- {
- _validator = validator;
- }
-
- ///
- /// Bind properties of two objects bidirectionally, converting the values using a converter.
- /// Synchronization can be intercepted by adding a validator.
- ///
- /// Object containing 1st property to bind
- /// Property of 1st object to bind
- /// Object containing 2nd property to bind
- /// Property of 2nd object to bind
- /// taking care of converting the synchronized value to the correct target format and back
- /// validator to intercept synchronization if the value does not match certain criteria
- public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName,
- IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter)
- {
- _validator = validator;
- }
-
- public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName))
- {
- _updatingField = true;
- Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName);
- _updatingField = false;
- }
- }
-
- public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName))
- {
- _updatingControl = true;
- Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName);
- _updatingControl = false;
- }
- }
-
- private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty)
- {
- PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty);
- PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty);
-
- if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite)
- {
- object bValue = sourcePropertyInfo.GetValue(sourceObject, null);
- if (_converter != null && bValue != null)
- {
- bValue = _converter.convert(bValue);
- }
-
- try
- {
- if (_validator == null || _validator.validate(bValue))
- {
- targetPropertyInfo.SetValue(targetObject, bValue, null);
- }
- }
- catch (Exception e)
- {
- throw new MemberAccessException(
- "Could not set property '" + targetProperty + "' to '" + bValue + "' [" + (bValue?.GetType().Name ?? string.Empty) + "] on " + targetObject +
- ". Probably other type than expected, IBindingCoverter to the rescue.", e);
- }
- }
- }
-
- private static PropertyInfo ResolvePropertyInfo(object obj, string property)
- {
- PropertyInfo ret = null;
- string[] properties = property.Split(".".ToCharArray());
- for (int i = 0; i < properties.Length; i++)
- {
- string prop = properties[i];
- ret = obj.GetType().GetProperty(prop);
- if (ret != null && ret.CanRead && i < prop.Length - 1)
- {
- obj = ret.GetValue(obj, null);
- }
- }
-
- return ret;
- }
-
- public IBindingConverter Converter
- {
- get { return _converter; }
- set { _converter = value; }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Reflection;
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Bidirectional binding of properties of two INotifyPropertyChanged instances.
+ /// This implementation synchronizes null values, too. If you do not want this
+ /// behavior (e.g. when binding to a
+ ///
+ public class BidirectionalBinding
+ {
+ private readonly INotifyPropertyChanged _controlObject;
+ private readonly INotifyPropertyChanged _fieldObject;
+ private readonly string _controlPropertyName;
+ private readonly string _fieldPropertyName;
+ private bool _updatingControl;
+ private bool _updatingField;
+ private IBindingConverter _converter;
+ private readonly IBindingValidator _validator;
+
+ ///
+ /// Whether or not null values are passed on to the other object.
+ ///
+ protected bool AllowSynchronizeNull = true;
+
+ ///
+ /// Bind properties of two objects bidirectionally
+ ///
+ /// Object containing 1st property to bind
+ /// Property of 1st object to bind
+ /// Object containing 2nd property to bind
+ /// Property of 2nd object to bind
+ public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName)
+ {
+ _controlObject = controlObject;
+ _fieldObject = fieldObject;
+ _controlPropertyName = controlPropertyName;
+ _fieldPropertyName = fieldPropertyName;
+
+ _controlObject.PropertyChanged += ControlPropertyChanged;
+ _fieldObject.PropertyChanged += FieldPropertyChanged;
+ }
+
+ ///
+ /// Bind properties of two objects bidirectionally, converting the values using a converter
+ ///
+ /// Object containing 1st property to bind
+ /// Property of 1st object to bind
+ /// Object containing 2nd property to bind
+ /// Property of 2nd object to bind
+ /// taking care of converting the synchronized value to the correct target format and back
+ public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName,
+ IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName)
+ {
+ _converter = converter;
+ }
+
+ ///
+ /// Bind properties of two objects bidirectionally, converting the values using a converter.
+ /// Synchronization can be intercepted by adding a validator.
+ ///
+ /// Object containing 1st property to bind
+ /// Property of 1st object to bind
+ /// Object containing 2nd property to bind
+ /// Property of 2nd object to bind
+ /// validator to intercept synchronization if the value does not match certain criteria
+ public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName,
+ IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName)
+ {
+ _validator = validator;
+ }
+
+ ///
+ /// Bind properties of two objects bidirectionally, converting the values using a converter.
+ /// Synchronization can be intercepted by adding a validator.
+ ///
+ /// Object containing 1st property to bind
+ /// Property of 1st object to bind
+ /// Object containing 2nd property to bind
+ /// Property of 2nd object to bind
+ /// taking care of converting the synchronized value to the correct target format and back
+ /// validator to intercept synchronization if the value does not match certain criteria
+ public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName,
+ IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter)
+ {
+ _validator = validator;
+ }
+
+ public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName))
+ {
+ _updatingField = true;
+ Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName);
+ _updatingField = false;
+ }
+ }
+
+ public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName))
+ {
+ _updatingControl = true;
+ Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName);
+ _updatingControl = false;
+ }
+ }
+
+ private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty)
+ {
+ PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty);
+ PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty);
+
+ if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite)
+ {
+ object bValue = sourcePropertyInfo.GetValue(sourceObject, null);
+ if (_converter != null && bValue != null)
+ {
+ bValue = _converter.convert(bValue);
+ }
+
+ try
+ {
+ if (_validator == null || _validator.validate(bValue))
+ {
+ targetPropertyInfo.SetValue(targetObject, bValue, null);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new MemberAccessException(
+ "Could not set property '" + targetProperty + "' to '" + bValue + "' [" + (bValue?.GetType().Name ?? string.Empty) + "] on " + targetObject +
+ ". Probably other type than expected, IBindingCoverter to the rescue.", e);
+ }
+ }
+ }
+
+ private static PropertyInfo ResolvePropertyInfo(object obj, string property)
+ {
+ PropertyInfo ret = null;
+ string[] properties = property.Split(".".ToCharArray());
+ for (int i = 0; i < properties.Length; i++)
+ {
+ string prop = properties[i];
+ ret = obj.GetType().GetProperty(prop);
+ if (ret != null && ret.CanRead && i < prop.Length - 1)
+ {
+ obj = ret.GetValue(obj, null);
+ }
+ }
+
+ return ret;
+ }
+
+ public IBindingConverter Converter
+ {
+ get { return _converter; }
+ set { _converter = value; }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs
index 6ce61c14d..0e8a35ddf 100644
--- a/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs
@@ -1,52 +1,52 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Converts decimal to double (%) and vice versa, e.g. 95f to 0.95d
- ///
- public class DecimalDoublePercentageConverter : AbstractBindingConverter
- {
- private static DecimalDoublePercentageConverter _uniqueInstance;
-
- private DecimalDoublePercentageConverter()
- {
- }
-
- protected override decimal convert(double o)
- {
- return Convert.ToDecimal(o) * 100;
- }
-
- protected override double convert(decimal o)
- {
- return Convert.ToDouble(o) / 100;
- }
-
- public static DecimalDoublePercentageConverter GetInstance()
- {
- return _uniqueInstance ??= new DecimalDoublePercentageConverter();
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Converts decimal to double (%) and vice versa, e.g. 95f to 0.95d
+ ///
+ public class DecimalDoublePercentageConverter : AbstractBindingConverter
+ {
+ private static DecimalDoublePercentageConverter _uniqueInstance;
+
+ private DecimalDoublePercentageConverter()
+ {
+ }
+
+ protected override decimal convert(double o)
+ {
+ return Convert.ToDecimal(o) * 100;
+ }
+
+ protected override double convert(decimal o)
+ {
+ return Convert.ToDouble(o) / 100;
+ }
+
+ public static DecimalDoublePercentageConverter GetInstance()
+ {
+ return _uniqueInstance ??= new DecimalDoublePercentageConverter();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/DecimalFloatConverter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/DecimalFloatConverter.cs
index 06721ae39..1f8e7a182 100644
--- a/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/DecimalFloatConverter.cs
@@ -1,52 +1,52 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Converts decimal to float and vice versa.
- ///
- public class DecimalFloatConverter : AbstractBindingConverter
- {
- private static DecimalFloatConverter _uniqueInstance;
-
- private DecimalFloatConverter()
- {
- }
-
- protected override decimal convert(float o)
- {
- return Convert.ToDecimal(o);
- }
-
- protected override float convert(decimal o)
- {
- return Convert.ToSingle(o);
- }
-
- public static DecimalFloatConverter GetInstance()
- {
- return _uniqueInstance ??= new DecimalFloatConverter();
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Converts decimal to float and vice versa.
+ ///
+ public class DecimalFloatConverter : AbstractBindingConverter
+ {
+ private static DecimalFloatConverter _uniqueInstance;
+
+ private DecimalFloatConverter()
+ {
+ }
+
+ protected override decimal convert(float o)
+ {
+ return Convert.ToDecimal(o);
+ }
+
+ protected override float convert(decimal o)
+ {
+ return Convert.ToSingle(o);
+ }
+
+ public static DecimalFloatConverter GetInstance()
+ {
+ return _uniqueInstance ??= new DecimalFloatConverter();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/DecimalIntConverter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/DecimalIntConverter.cs
index 5986346b4..882ceaac9 100644
--- a/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/DecimalIntConverter.cs
@@ -1,52 +1,52 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Converts decimal to int and vice versa.
- ///
- public class DecimalIntConverter : AbstractBindingConverter
- {
- private static DecimalIntConverter _uniqueInstance;
-
- private DecimalIntConverter()
- {
- }
-
- protected override decimal convert(int o)
- {
- return Convert.ToDecimal(o);
- }
-
- protected override int convert(decimal o)
- {
- return Convert.ToInt32(o);
- }
-
- public static DecimalIntConverter GetInstance()
- {
- return _uniqueInstance ??= new DecimalIntConverter();
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Converts decimal to int and vice versa.
+ ///
+ public class DecimalIntConverter : AbstractBindingConverter
+ {
+ private static DecimalIntConverter _uniqueInstance;
+
+ private DecimalIntConverter()
+ {
+ }
+
+ protected override decimal convert(int o)
+ {
+ return Convert.ToDecimal(o);
+ }
+
+ protected override int convert(decimal o)
+ {
+ return Convert.ToInt32(o);
+ }
+
+ public static DecimalIntConverter GetInstance()
+ {
+ return _uniqueInstance ??= new DecimalIntConverter();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/IBindingConverter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/IBindingConverter.cs
index f9e1f0ffd..b5f5bb621 100644
--- a/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/IBindingConverter.cs
@@ -1,33 +1,33 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Interface for a bidirectional converter, for use with BidirectionalBinding.
- /// convert(object) implementation must deal with both directions.
- /// see DecimalIntConverter
- ///
- public interface IBindingConverter
- {
- object convert(object o);
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Interface for a bidirectional converter, for use with BidirectionalBinding.
+ /// convert(object) implementation must deal with both directions.
+ /// see DecimalIntConverter
+ ///
+ public interface IBindingConverter
+ {
+ object convert(object o);
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/IBindingValidator.cs
similarity index 94%
rename from src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/IBindingValidator.cs
index 3981f0c17..6e53a7ea6 100644
--- a/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/IBindingValidator.cs
@@ -1,34 +1,34 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Interface for a bidirectional validator, for use with BidirectionalBinding.
- /// Useful if you do not want to synchronize values which would be illegal on
- /// one of the bound objects (e.g. null value on some form components)
- /// see NotNullValidator
- ///
- public interface IBindingValidator
- {
- bool validate(object o);
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Interface for a bidirectional validator, for use with BidirectionalBinding.
+ /// Useful if you do not want to synchronize values which would be illegal on
+ /// one of the bound objects (e.g. null value on some form components)
+ /// see NotNullValidator
+ ///
+ public interface IBindingValidator
+ {
+ bool validate(object o);
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs b/src/Greenshot.Editor/Drawing/Fields/Binding/NotNullValidator.cs
similarity index 94%
rename from src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs
rename to src/Greenshot.Editor/Drawing/Fields/Binding/NotNullValidator.cs
index 09cc898a9..426a560ee 100644
--- a/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Binding/NotNullValidator.cs
@@ -1,45 +1,45 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-namespace Greenshot.Drawing.Fields.Binding
-{
- ///
- /// Validates a value not to be null.
- ///
- public class NotNullValidator : IBindingValidator
- {
- private static NotNullValidator _uniqueInstance;
-
- private NotNullValidator()
- {
- }
-
- public bool validate(object o)
- {
- return o != null;
- }
-
- public static NotNullValidator GetInstance()
- {
- return _uniqueInstance ??= new NotNullValidator();
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Editor.Drawing.Fields.Binding
+{
+ ///
+ /// Validates a value not to be null.
+ ///
+ public class NotNullValidator : IBindingValidator
+ {
+ private static NotNullValidator _uniqueInstance;
+
+ private NotNullValidator()
+ {
+ }
+
+ public bool validate(object o)
+ {
+ return o != null;
+ }
+
+ public static NotNullValidator GetInstance()
+ {
+ return _uniqueInstance ??= new NotNullValidator();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/Field.cs b/src/Greenshot.Editor/Drawing/Fields/Field.cs
similarity index 96%
rename from src/Greenshot/Drawing/Fields/Field.cs
rename to src/Greenshot.Editor/Drawing/Fields/Field.cs
index b06efa77a..c3870c54c 100644
--- a/src/Greenshot/Drawing/Fields/Field.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/Field.cs
@@ -1,128 +1,128 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Fields
-{
- ///
- /// Represents a single field of a drawable element, i.e.
- /// line thickness of a rectangle.
- ///
- [Serializable]
- public class Field : IField
- {
- [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged;
-
- private object _myValue;
-
- public object Value
- {
- get { return _myValue; }
- set
- {
- if (!Equals(_myValue, value))
- {
- _myValue = value;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
- }
- }
- }
-
- public IFieldType FieldType { get; set; }
- public string Scope { get; set; }
-
- ///
- /// Constructs a new Field instance, usually you should be using FieldFactory
- /// to create Fields.
- ///
- /// FieldType of the Field to be created
- /// The scope to which the value of this Field is relevant.
- /// Depending on the scope the Field's value may be shared for other elements
- /// containing the same FieldType for defaulting to the last used value.
- /// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value
- /// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer))
- ///
- public Field(IFieldType fieldType, Type scope)
- {
- FieldType = fieldType;
- Scope = scope.Name;
- }
-
- public Field(IFieldType fieldType, string scope)
- {
- FieldType = fieldType;
- Scope = scope;
- }
-
- public Field(IFieldType fieldType)
- {
- FieldType = fieldType;
- }
-
- ///
- /// Returns true if this field holds a value other than null.
- ///
- public bool HasValue => Value != null;
-
- ///
- /// Creates a flat clone of this Field. The fields value itself is not cloned.
- ///
- ///
- public Field Clone()
- {
- return new Field(FieldType, Scope)
- {
- Value = Value
- };
- }
-
- public override int GetHashCode()
- {
- int hashCode = 0;
- unchecked
- {
- hashCode += 1000000009 * FieldType.GetHashCode();
- if (Scope != null)
- hashCode += 1000000021 * Scope.GetHashCode();
- }
-
- return hashCode;
- }
-
- public override bool Equals(object obj)
- {
- if (!(obj is Field other))
- {
- return false;
- }
-
- return FieldType == other.FieldType && Equals(Scope, other.Scope);
- }
-
- public override string ToString()
- {
- return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using Greenshot.Base.Interfaces.Drawing;
+
+namespace Greenshot.Editor.Drawing.Fields
+{
+ ///
+ /// Represents a single field of a drawable element, i.e.
+ /// line thickness of a rectangle.
+ ///
+ [Serializable]
+ public class Field : IField
+ {
+ [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged;
+
+ private object _myValue;
+
+ public object Value
+ {
+ get { return _myValue; }
+ set
+ {
+ if (!Equals(_myValue, value))
+ {
+ _myValue = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
+ }
+ }
+ }
+
+ public IFieldType FieldType { get; set; }
+ public string Scope { get; set; }
+
+ ///
+ /// Constructs a new Field instance, usually you should be using FieldFactory
+ /// to create Fields.
+ ///
+ /// FieldType of the Field to be created
+ /// The scope to which the value of this Field is relevant.
+ /// Depending on the scope the Field's value may be shared for other elements
+ /// containing the same FieldType for defaulting to the last used value.
+ /// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value
+ /// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer))
+ ///
+ public Field(IFieldType fieldType, Type scope)
+ {
+ FieldType = fieldType;
+ Scope = scope.Name;
+ }
+
+ public Field(IFieldType fieldType, string scope)
+ {
+ FieldType = fieldType;
+ Scope = scope;
+ }
+
+ public Field(IFieldType fieldType)
+ {
+ FieldType = fieldType;
+ }
+
+ ///
+ /// Returns true if this field holds a value other than null.
+ ///
+ public bool HasValue => Value != null;
+
+ ///
+ /// Creates a flat clone of this Field. The fields value itself is not cloned.
+ ///
+ ///
+ public Field Clone()
+ {
+ return new Field(FieldType, Scope)
+ {
+ Value = Value
+ };
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = 0;
+ unchecked
+ {
+ hashCode += 1000000009 * FieldType.GetHashCode();
+ if (Scope != null)
+ hashCode += 1000000021 * Scope.GetHashCode();
+ }
+
+ return hashCode;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is Field other))
+ {
+ return false;
+ }
+
+ return FieldType == other.FieldType && Equals(Scope, other.Scope);
+ }
+
+ public override string ToString()
+ {
+ return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/FieldAggregator.cs b/src/Greenshot.Editor/Drawing/Fields/FieldAggregator.cs
similarity index 96%
rename from src/Greenshot/Drawing/Fields/FieldAggregator.cs
rename to src/Greenshot.Editor/Drawing/Fields/FieldAggregator.cs
index ee3c79d00..2df16d46f 100644
--- a/src/Greenshot/Drawing/Fields/FieldAggregator.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/FieldAggregator.cs
@@ -1,224 +1,224 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using Greenshot.Configuration;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using Greenshot.Base.IniFile;
-using Greenshot.Base.Interfaces;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Fields
-{
- ///
- /// Represents the current set of properties for the editor.
- /// When one of EditorProperties' properties is updated, the change will be promoted
- /// to all bound elements.
- /// * If an element is selected:
- /// This class represents the element's properties
- /// * I n>1 elements are selected:
- /// This class represents the properties of all elements.
- /// Properties that do not apply for ALL selected elements are null (or 0 respectively)
- /// If the property values of the selected elements differ, the value of the last bound element wins.
- ///
- [Serializable]
- public sealed class FieldAggregator : AbstractFieldHolder
- {
- private readonly IDrawableContainerList _boundContainers;
- private bool _internalUpdateRunning;
-
- private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection();
-
- public FieldAggregator(ISurface parent)
- {
- foreach (var fieldType in FieldType.Values)
- {
- var field = new Field(fieldType, GetType());
- AddField(field);
- }
-
- _boundContainers = new DrawableContainerList
- {
- Parent = parent
- };
- }
-
- public override void AddField(IField field)
- {
- base.AddField(field);
- field.PropertyChanged += OwnPropertyChanged;
- }
-
- public void BindElements(IDrawableContainerList dcs)
- {
- foreach (var dc in dcs)
- {
- BindElement(dc);
- }
- }
-
- public void BindElement(IDrawableContainer dc)
- {
- if (!(dc is DrawableContainer container) || _boundContainers.Contains(container))
- {
- return;
- }
-
- _boundContainers.Add(container);
- container.ChildrenChanged += delegate { UpdateFromBoundElements(); };
- UpdateFromBoundElements();
- }
-
- public void BindAndUpdateElement(IDrawableContainer dc)
- {
- UpdateElement(dc);
- BindElement(dc);
- }
-
- public void UpdateElement(IDrawableContainer dc)
- {
- if (!(dc is DrawableContainer container))
- {
- return;
- }
-
- _internalUpdateRunning = true;
- foreach (var field in GetFields())
- {
- if (container.HasField(field.FieldType) && field.HasValue)
- {
- //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value);
- container.SetFieldValue(field.FieldType, field.Value);
- }
- }
-
- _internalUpdateRunning = false;
- }
-
- public void UnbindElement(IDrawableContainer dc)
- {
- if (_boundContainers.Contains(dc))
- {
- _boundContainers.Remove(dc);
- UpdateFromBoundElements();
- }
- }
-
- public void Clear()
- {
- ClearFields();
- _boundContainers.Clear();
- UpdateFromBoundElements();
- }
-
- ///
- /// sets all field values to null, however does not remove fields
- ///
- private void ClearFields()
- {
- _internalUpdateRunning = true;
- foreach (var field in GetFields())
- {
- field.Value = null;
- }
-
- _internalUpdateRunning = false;
- }
-
- ///
- /// Updates this instance using the respective fields from the bound elements.
- /// Fields that do not apply to every bound element are set to null, or 0 respectively.
- /// All other fields will be set to the field value of the least bound element.
- ///
- private void UpdateFromBoundElements()
- {
- ClearFields();
- _internalUpdateRunning = true;
- foreach (var field in FindCommonFields())
- {
- SetFieldValue(field.FieldType, field.Value);
- }
-
- _internalUpdateRunning = false;
- }
-
- private IList FindCommonFields()
- {
- IList returnFields = null;
- if (_boundContainers.Count > 0)
- {
- // take all fields from the least selected container...
- if (_boundContainers[_boundContainers.Count - 1] is DrawableContainer leastSelectedContainer)
- {
- returnFields = leastSelectedContainer.GetFields();
- for (int i = 0; i < _boundContainers.Count - 1; i++)
- {
- if (!(_boundContainers[i] is DrawableContainer dc)) continue;
- IList fieldsToRemove = new List();
- foreach (IField field in returnFields)
- {
- // ... throw out those that do not apply to one of the other containers
- if (!dc.HasField(field.FieldType))
- {
- fieldsToRemove.Add(field);
- }
- }
-
- foreach (var field in fieldsToRemove)
- {
- returnFields.Remove(field);
- }
- }
- }
- }
-
- return returnFields ?? new List();
- }
-
- public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea)
- {
- IField field = (IField) sender;
- if (_internalUpdateRunning || field.Value == null)
- {
- return;
- }
-
- foreach (var drawableContainer1 in _boundContainers.ToList())
- {
- var drawableContainer = (DrawableContainer) drawableContainer1;
- if (!drawableContainer.HasField(field.FieldType))
- {
- continue;
- }
-
- IField drawableContainerField = drawableContainer.GetField(field.FieldType);
- // Notify before change, so we can e.g. invalidate the area
- drawableContainer.BeforeFieldChange(drawableContainerField, field.Value);
-
- drawableContainerField.Value = field.Value;
- // update last used from DC field, so that scope is honored
- EditorConfig.UpdateLastFieldValue(drawableContainerField);
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using Greenshot.Base.IniFile;
+using Greenshot.Base.Interfaces;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Configuration;
+
+namespace Greenshot.Editor.Drawing.Fields
+{
+ ///
+ /// Represents the current set of properties for the editor.
+ /// When one of EditorProperties' properties is updated, the change will be promoted
+ /// to all bound elements.
+ /// * If an element is selected:
+ /// This class represents the element's properties
+ /// * I n>1 elements are selected:
+ /// This class represents the properties of all elements.
+ /// Properties that do not apply for ALL selected elements are null (or 0 respectively)
+ /// If the property values of the selected elements differ, the value of the last bound element wins.
+ ///
+ [Serializable]
+ public sealed class FieldAggregator : AbstractFieldHolder
+ {
+ private readonly IDrawableContainerList _boundContainers;
+ private bool _internalUpdateRunning;
+
+ private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection();
+
+ public FieldAggregator(ISurface parent)
+ {
+ foreach (var fieldType in FieldType.Values)
+ {
+ var field = new Field(fieldType, GetType());
+ AddField(field);
+ }
+
+ _boundContainers = new DrawableContainerList
+ {
+ Parent = parent
+ };
+ }
+
+ public override void AddField(IField field)
+ {
+ base.AddField(field);
+ field.PropertyChanged += OwnPropertyChanged;
+ }
+
+ public void BindElements(IDrawableContainerList dcs)
+ {
+ foreach (var dc in dcs)
+ {
+ BindElement(dc);
+ }
+ }
+
+ public void BindElement(IDrawableContainer dc)
+ {
+ if (!(dc is DrawableContainer container) || _boundContainers.Contains(container))
+ {
+ return;
+ }
+
+ _boundContainers.Add(container);
+ container.ChildrenChanged += delegate { UpdateFromBoundElements(); };
+ UpdateFromBoundElements();
+ }
+
+ public void BindAndUpdateElement(IDrawableContainer dc)
+ {
+ UpdateElement(dc);
+ BindElement(dc);
+ }
+
+ public void UpdateElement(IDrawableContainer dc)
+ {
+ if (!(dc is DrawableContainer container))
+ {
+ return;
+ }
+
+ _internalUpdateRunning = true;
+ foreach (var field in GetFields())
+ {
+ if (container.HasField(field.FieldType) && field.HasValue)
+ {
+ //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value);
+ container.SetFieldValue(field.FieldType, field.Value);
+ }
+ }
+
+ _internalUpdateRunning = false;
+ }
+
+ public void UnbindElement(IDrawableContainer dc)
+ {
+ if (_boundContainers.Contains(dc))
+ {
+ _boundContainers.Remove(dc);
+ UpdateFromBoundElements();
+ }
+ }
+
+ public void Clear()
+ {
+ ClearFields();
+ _boundContainers.Clear();
+ UpdateFromBoundElements();
+ }
+
+ ///
+ /// sets all field values to null, however does not remove fields
+ ///
+ private void ClearFields()
+ {
+ _internalUpdateRunning = true;
+ foreach (var field in GetFields())
+ {
+ field.Value = null;
+ }
+
+ _internalUpdateRunning = false;
+ }
+
+ ///
+ /// Updates this instance using the respective fields from the bound elements.
+ /// Fields that do not apply to every bound element are set to null, or 0 respectively.
+ /// All other fields will be set to the field value of the least bound element.
+ ///
+ private void UpdateFromBoundElements()
+ {
+ ClearFields();
+ _internalUpdateRunning = true;
+ foreach (var field in FindCommonFields())
+ {
+ SetFieldValue(field.FieldType, field.Value);
+ }
+
+ _internalUpdateRunning = false;
+ }
+
+ private IList FindCommonFields()
+ {
+ IList returnFields = null;
+ if (_boundContainers.Count > 0)
+ {
+ // take all fields from the least selected container...
+ if (_boundContainers[_boundContainers.Count - 1] is DrawableContainer leastSelectedContainer)
+ {
+ returnFields = leastSelectedContainer.GetFields();
+ for (int i = 0; i < _boundContainers.Count - 1; i++)
+ {
+ if (!(_boundContainers[i] is DrawableContainer dc)) continue;
+ IList fieldsToRemove = new List();
+ foreach (IField field in returnFields)
+ {
+ // ... throw out those that do not apply to one of the other containers
+ if (!dc.HasField(field.FieldType))
+ {
+ fieldsToRemove.Add(field);
+ }
+ }
+
+ foreach (var field in fieldsToRemove)
+ {
+ returnFields.Remove(field);
+ }
+ }
+ }
+ }
+
+ return returnFields ?? new List();
+ }
+
+ public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea)
+ {
+ IField field = (IField) sender;
+ if (_internalUpdateRunning || field.Value == null)
+ {
+ return;
+ }
+
+ foreach (var drawableContainer1 in _boundContainers.ToList())
+ {
+ var drawableContainer = (DrawableContainer) drawableContainer1;
+ if (!drawableContainer.HasField(field.FieldType))
+ {
+ continue;
+ }
+
+ IField drawableContainerField = drawableContainer.GetField(field.FieldType);
+ // Notify before change, so we can e.g. invalidate the area
+ drawableContainer.BeforeFieldChange(drawableContainerField, field.Value);
+
+ drawableContainerField.Value = field.Value;
+ // update last used from DC field, so that scope is honored
+ EditorConfig.UpdateLastFieldValue(drawableContainerField);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Fields/FieldType.cs b/src/Greenshot.Editor/Drawing/Fields/FieldType.cs
similarity index 96%
rename from src/Greenshot/Drawing/Fields/FieldType.cs
rename to src/Greenshot.Editor/Drawing/Fields/FieldType.cs
index ecc3f1781..c3b732f4b 100644
--- a/src/Greenshot/Drawing/Fields/FieldType.cs
+++ b/src/Greenshot.Editor/Drawing/Fields/FieldType.cs
@@ -1,106 +1,106 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Fields
-{
- ///
- /// Defines all FieldTypes + their default value.
- /// (The additional value is why this is not an enum)
- ///
- [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 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
- };
-
- public string Name { get; set; }
-
- private FieldType(string name)
- {
- Name = name;
- }
-
- public override string ToString()
- {
- return Name;
- }
-
- public override int GetHashCode()
- {
- int hashCode = 0;
- unchecked
- {
- if (Name != null)
- hashCode += 1000000009 * Name.GetHashCode();
- }
-
- return hashCode;
- }
-
- public override bool Equals(object obj)
- {
- FieldType other = obj as FieldType;
- if (other == null)
- {
- return false;
- }
-
- return Equals(Name, other.Name);
- }
-
- public static bool operator ==(FieldType a, FieldType b)
- {
- return Equals(a, b);
- }
-
- public static bool operator !=(FieldType a, FieldType b)
- {
- return !Equals(a, b);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using Greenshot.Base.Interfaces.Drawing;
+
+namespace Greenshot.Editor.Drawing.Fields
+{
+ ///
+ /// Defines all FieldTypes + their default value.
+ /// (The additional value is why this is not an enum)
+ ///
+ [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 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
+ };
+
+ public string Name { get; set; }
+
+ private FieldType(string name)
+ {
+ Name = name;
+ }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = 0;
+ unchecked
+ {
+ if (Name != null)
+ hashCode += 1000000009 * Name.GetHashCode();
+ }
+
+ return hashCode;
+ }
+
+ public override bool Equals(object obj)
+ {
+ FieldType other = obj as FieldType;
+ if (other == null)
+ {
+ return false;
+ }
+
+ return Equals(Name, other.Name);
+ }
+
+ public static bool operator ==(FieldType a, FieldType b)
+ {
+ return Equals(a, b);
+ }
+
+ public static bool operator !=(FieldType a, FieldType b)
+ {
+ return !Equals(a, b);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/FilterContainer.cs b/src/Greenshot.Editor/Drawing/FilterContainer.cs
similarity index 95%
rename from src/Greenshot/Drawing/FilterContainer.cs
rename to src/Greenshot.Editor/Drawing/FilterContainer.cs
index c8cab4e4c..3bdb5a5fd 100644
--- a/src/Greenshot/Drawing/FilterContainer.cs
+++ b/src/Greenshot.Editor/Drawing/FilterContainer.cs
@@ -1,115 +1,115 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using System.Drawing.Drawing2D;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// empty container for filter-only elements
- ///
- [Serializable]
- public abstract class FilterContainer : DrawableContainer
- {
- public enum PreparedFilterMode
- {
- OBFUSCATE,
- HIGHLIGHT
- };
-
- public enum PreparedFilter
- {
- BLUR,
- PIXELIZE,
- TEXT_HIGHTLIGHT,
- AREA_HIGHLIGHT,
- GRAYSCALE,
- MAGNIFICATION
- };
-
- public FilterContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- Init();
- }
-
- private void Init()
- {
- CreateDefaultAdorners();
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 0);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
- AddField(GetType(), FieldType.SHADOW, false);
- }
-
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
- if (lineVisible)
- {
- graphics.SmoothingMode = SmoothingMode.HighSpeed;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
- //draw shadow first
- if (shadow)
- {
- int basealpha = 100;
- int alpha = basealpha;
- int steps = 5;
- int currentStep = lineVisible ? 1 : 0;
- while (currentStep <= steps)
- {
- using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
- Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height);
- graphics.DrawRectangle(shadowPen, shadowRect);
- currentStep++;
- alpha -= basealpha / steps;
- }
- }
-
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- if (lineThickness > 0)
- {
- using Pen pen = new Pen(lineColor, lineThickness);
- graphics.DrawRectangle(pen, rect);
- }
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// empty container for filter-only elements
+ ///
+ [Serializable]
+ public abstract class FilterContainer : DrawableContainer
+ {
+ public enum PreparedFilterMode
+ {
+ OBFUSCATE,
+ HIGHLIGHT
+ };
+
+ public enum PreparedFilter
+ {
+ BLUR,
+ PIXELIZE,
+ TEXT_HIGHTLIGHT,
+ AREA_HIGHLIGHT,
+ GRAYSCALE,
+ MAGNIFICATION
+ };
+
+ public FilterContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ Init();
+ }
+
+ private void Init()
+ {
+ CreateDefaultAdorners();
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 0);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
+ AddField(GetType(), FieldType.SHADOW, false);
+ }
+
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
+ if (lineVisible)
+ {
+ graphics.SmoothingMode = SmoothingMode.HighSpeed;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+ //draw shadow first
+ if (shadow)
+ {
+ int basealpha = 100;
+ int alpha = basealpha;
+ int steps = 5;
+ int currentStep = lineVisible ? 1 : 0;
+ while (currentStep <= steps)
+ {
+ using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
+ Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height);
+ graphics.DrawRectangle(shadowPen, shadowRect);
+ currentStep++;
+ alpha -= basealpha / steps;
+ }
+ }
+
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ if (lineThickness > 0)
+ {
+ using Pen pen = new Pen(lineColor, lineThickness);
+ graphics.DrawRectangle(pen, rect);
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/AbstractFilter.cs b/src/Greenshot.Editor/Drawing/Filters/AbstractFilter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Filters/AbstractFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/AbstractFilter.cs
index 4dfb6d66c..17517b971 100644
--- a/src/Greenshot/Drawing/Filters/AbstractFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/AbstractFilter.cs
@@ -1,83 +1,83 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-
-namespace Greenshot.Drawing.Filters
-{
- ///
- /// Graphical filter which can be added to DrawableContainer.
- /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call
- /// OnPropertyChanged whenever a public property has been changed.
- ///
- [Serializable]
- public abstract class AbstractFilter : AbstractFieldHolder, IFilter
- {
- [NonSerialized] private PropertyChangedEventHandler propertyChanged;
-
- public event PropertyChangedEventHandler PropertyChanged
- {
- add { propertyChanged += value; }
- remove { propertyChanged -= value; }
- }
-
- private bool invert;
-
- public bool Invert
- {
- get { return invert; }
- set
- {
- invert = value;
- OnPropertyChanged("Invert");
- }
- }
-
- protected DrawableContainer parent;
-
- public DrawableContainer Parent
- {
- get { return parent; }
- set { parent = value; }
- }
-
- public AbstractFilter(DrawableContainer parent)
- {
- this.parent = parent;
- }
-
- public DrawableContainer GetParent()
- {
- return parent;
- }
-
- public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode);
-
- protected void OnPropertyChanged(string propertyName)
- {
- propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ ///
+ /// Graphical filter which can be added to DrawableContainer.
+ /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call
+ /// OnPropertyChanged whenever a public property has been changed.
+ ///
+ [Serializable]
+ public abstract class AbstractFilter : AbstractFieldHolder, IFilter
+ {
+ [NonSerialized] private PropertyChangedEventHandler propertyChanged;
+
+ public event PropertyChangedEventHandler PropertyChanged
+ {
+ add { propertyChanged += value; }
+ remove { propertyChanged -= value; }
+ }
+
+ private bool invert;
+
+ public bool Invert
+ {
+ get { return invert; }
+ set
+ {
+ invert = value;
+ OnPropertyChanged("Invert");
+ }
+ }
+
+ protected DrawableContainer parent;
+
+ public DrawableContainer Parent
+ {
+ get { return parent; }
+ set { parent = value; }
+ }
+
+ public AbstractFilter(DrawableContainer parent)
+ {
+ this.parent = parent;
+ }
+
+ public DrawableContainer GetParent()
+ {
+ return parent;
+ }
+
+ public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode);
+
+ protected void OnPropertyChanged(string propertyName)
+ {
+ propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/BlurFilter.cs b/src/Greenshot.Editor/Drawing/Filters/BlurFilter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Filters/BlurFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/BlurFilter.cs
index 5ecbd4ed9..ac0e26a64 100644
--- a/src/Greenshot/Drawing/Filters/BlurFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/BlurFilter.cs
@@ -1,83 +1,83 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using Greenshot.Drawing.Fields;
-using System.Drawing.Drawing2D;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Base.UnmanagedHelpers;
-
-namespace Greenshot.Drawing.Filters
-{
- [Serializable]
- public class BlurFilter : AbstractFilter
- {
- public double previewQuality;
-
- public double PreviewQuality
- {
- get { return previewQuality; }
- set
- {
- previewQuality = value;
- OnPropertyChanged("PreviewQuality");
- }
- }
-
- public BlurFilter(DrawableContainer parent) : base(parent)
- {
- AddField(GetType(), FieldType.BLUR_RADIUS, 3);
- AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d);
- }
-
- public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
- {
- int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
- Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
- if (applyRect.Width == 0 || applyRect.Height == 0)
- {
- return;
- }
-
- GraphicsState state = graphics.Save();
- if (Invert)
- {
- graphics.SetClip(applyRect);
- graphics.ExcludeClip(rect);
- }
-
- if (GDIplus.IsBlurPossible(blurRadius))
- {
- GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false);
- }
- else
- {
- using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect);
- ImageHelper.ApplyBoxBlur(fastBitmap, blurRadius);
- fastBitmap.DrawTo(graphics, applyRect);
- }
-
- graphics.Restore(state);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Base.UnmanagedHelpers;
+using Greenshot.Editor.Drawing.Fields;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ [Serializable]
+ public class BlurFilter : AbstractFilter
+ {
+ public double previewQuality;
+
+ public double PreviewQuality
+ {
+ get { return previewQuality; }
+ set
+ {
+ previewQuality = value;
+ OnPropertyChanged("PreviewQuality");
+ }
+ }
+
+ public BlurFilter(DrawableContainer parent) : base(parent)
+ {
+ AddField(GetType(), FieldType.BLUR_RADIUS, 3);
+ AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d);
+ }
+
+ public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
+ {
+ int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
+ Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
+ if (applyRect.Width == 0 || applyRect.Height == 0)
+ {
+ return;
+ }
+
+ GraphicsState state = graphics.Save();
+ if (Invert)
+ {
+ graphics.SetClip(applyRect);
+ graphics.ExcludeClip(rect);
+ }
+
+ if (GDIplus.IsBlurPossible(blurRadius))
+ {
+ GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false);
+ }
+ else
+ {
+ using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect);
+ ImageHelper.ApplyBoxBlur(fastBitmap, blurRadius);
+ fastBitmap.DrawTo(graphics, applyRect);
+ }
+
+ graphics.Restore(state);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/BrightnessFilter.cs b/src/Greenshot.Editor/Drawing/Filters/BrightnessFilter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Filters/BrightnessFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/BrightnessFilter.cs
index b372c42e3..cfdf7b025 100644
--- a/src/Greenshot/Drawing/Filters/BrightnessFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/BrightnessFilter.cs
@@ -1,73 +1,73 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using Greenshot.Drawing.Fields;
-using System.Drawing.Imaging;
-using System.Drawing.Drawing2D;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Filters
-{
- [Serializable()]
- public class BrightnessFilter : AbstractFilter
- {
- public BrightnessFilter(DrawableContainer parent) : base(parent)
- {
- AddField(GetType(), FieldType.BRIGHTNESS, 0.9d);
- }
-
- ///
- /// Implements the Apply code for the Brightness Filet
- ///
- ///
- ///
- ///
- ///
- public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
- {
- Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
-
- if (applyRect.Width == 0 || applyRect.Height == 0)
- {
- // nothing to do
- return;
- }
-
- GraphicsState state = graphics.Save();
- if (Invert)
- {
- graphics.SetClip(applyRect);
- graphics.ExcludeClip(rect);
- }
-
- float brightness = GetFieldValueAsFloat(FieldType.BRIGHTNESS);
- using (ImageAttributes ia = ImageHelper.CreateAdjustAttributes(brightness, 1f, 1f))
- {
- graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia);
- }
-
- graphics.Restore(state);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ [Serializable()]
+ public class BrightnessFilter : AbstractFilter
+ {
+ public BrightnessFilter(DrawableContainer parent) : base(parent)
+ {
+ AddField(GetType(), FieldType.BRIGHTNESS, 0.9d);
+ }
+
+ ///
+ /// Implements the Apply code for the Brightness Filet
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
+ {
+ Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
+
+ if (applyRect.Width == 0 || applyRect.Height == 0)
+ {
+ // nothing to do
+ return;
+ }
+
+ GraphicsState state = graphics.Save();
+ if (Invert)
+ {
+ graphics.SetClip(applyRect);
+ graphics.ExcludeClip(rect);
+ }
+
+ float brightness = GetFieldValueAsFloat(FieldType.BRIGHTNESS);
+ using (ImageAttributes ia = ImageHelper.CreateAdjustAttributes(brightness, 1f, 1f))
+ {
+ graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia);
+ }
+
+ graphics.Restore(state);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs
similarity index 95%
rename from src/Greenshot/Drawing/Filters/GrayscaleFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs
index 356a91a19..5ed195fc7 100644
--- a/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs
@@ -1,90 +1,90 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Imaging;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Filters
-{
- ///
- /// Description of GrayscaleFilter.
- ///
- [Serializable()]
- public class GrayscaleFilter : AbstractFilter
- {
- public GrayscaleFilter(DrawableContainer parent) : base(parent)
- {
- }
-
- public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
- {
- Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
-
- if (applyRect.Width == 0 || applyRect.Height == 0)
- {
- // nothing to do
- return;
- }
-
- GraphicsState state = graphics.Save();
- if (Invert)
- {
- graphics.SetClip(applyRect);
- graphics.ExcludeClip(rect);
- }
-
- ColorMatrix grayscaleMatrix = new ColorMatrix(new[]
- {
- new[]
- {
- .3f, .3f, .3f, 0, 0
- },
- new[]
- {
- .59f, .59f, .59f, 0, 0
- },
- new[]
- {
- .11f, .11f, .11f, 0, 0
- },
- new float[]
- {
- 0, 0, 0, 1, 0
- },
- new float[]
- {
- 0, 0, 0, 0, 1
- }
- });
- using (ImageAttributes ia = new ImageAttributes())
- {
- ia.SetColorMatrix(grayscaleMatrix);
- graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia);
- }
-
- graphics.Restore(state);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ ///
+ /// Description of GrayscaleFilter.
+ ///
+ [Serializable()]
+ public class GrayscaleFilter : AbstractFilter
+ {
+ public GrayscaleFilter(DrawableContainer parent) : base(parent)
+ {
+ }
+
+ public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
+ {
+ Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
+
+ if (applyRect.Width == 0 || applyRect.Height == 0)
+ {
+ // nothing to do
+ return;
+ }
+
+ GraphicsState state = graphics.Save();
+ if (Invert)
+ {
+ graphics.SetClip(applyRect);
+ graphics.ExcludeClip(rect);
+ }
+
+ ColorMatrix grayscaleMatrix = new ColorMatrix(new[]
+ {
+ new[]
+ {
+ .3f, .3f, .3f, 0, 0
+ },
+ new[]
+ {
+ .59f, .59f, .59f, 0, 0
+ },
+ new[]
+ {
+ .11f, .11f, .11f, 0, 0
+ },
+ new float[]
+ {
+ 0, 0, 0, 1, 0
+ },
+ new float[]
+ {
+ 0, 0, 0, 0, 1
+ }
+ });
+ using (ImageAttributes ia = new ImageAttributes())
+ {
+ ia.SetColorMatrix(grayscaleMatrix);
+ graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia);
+ }
+
+ graphics.Restore(state);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/HighlightFilter.cs b/src/Greenshot.Editor/Drawing/Filters/HighlightFilter.cs
similarity index 95%
rename from src/Greenshot/Drawing/Filters/HighlightFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/HighlightFilter.cs
index e42e1b60a..32337fb98 100644
--- a/src/Greenshot/Drawing/Filters/HighlightFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/HighlightFilter.cs
@@ -1,82 +1,82 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using Greenshot.Drawing.Fields;
-using System.Drawing.Drawing2D;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Filters
-{
- [Serializable()]
- public class HighlightFilter : AbstractFilter
- {
- public HighlightFilter(DrawableContainer parent) : base(parent)
- {
- AddField(GetType(), FieldType.FILL_COLOR, Color.Yellow);
- }
-
- ///
- /// Implements the Apply code for the Brightness Filet
- ///
- ///
- ///
- ///
- ///
- public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
- {
- Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
-
- if (applyRect.Width == 0 || applyRect.Height == 0)
- {
- // nothing to do
- return;
- }
-
- GraphicsState state = graphics.Save();
- if (Invert)
- {
- graphics.SetClip(applyRect);
- graphics.ExcludeClip(rect);
- }
-
- using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect))
- {
- Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
- for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++)
- {
- for (int x = fastBitmap.Left; x < fastBitmap.Right; x++)
- {
- Color color = fastBitmap.GetColorAt(x, y);
- color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B));
- fastBitmap.SetColorAt(x, y, color);
- }
- }
-
- fastBitmap.DrawTo(graphics, applyRect.Location);
- }
-
- graphics.Restore(state);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ [Serializable()]
+ public class HighlightFilter : AbstractFilter
+ {
+ public HighlightFilter(DrawableContainer parent) : base(parent)
+ {
+ AddField(GetType(), FieldType.FILL_COLOR, Color.Yellow);
+ }
+
+ ///
+ /// Implements the Apply code for the Brightness Filet
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
+ {
+ Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
+
+ if (applyRect.Width == 0 || applyRect.Height == 0)
+ {
+ // nothing to do
+ return;
+ }
+
+ GraphicsState state = graphics.Save();
+ if (Invert)
+ {
+ graphics.SetClip(applyRect);
+ graphics.ExcludeClip(rect);
+ }
+
+ using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect))
+ {
+ Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+ for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++)
+ {
+ for (int x = fastBitmap.Left; x < fastBitmap.Right; x++)
+ {
+ Color color = fastBitmap.GetColorAt(x, y);
+ color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B));
+ fastBitmap.SetColorAt(x, y, color);
+ }
+ }
+
+ fastBitmap.DrawTo(graphics, applyRect.Location);
+ }
+
+ graphics.Restore(state);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/IFilter.cs b/src/Greenshot.Editor/Drawing/Filters/IFilter.cs
similarity index 94%
rename from src/Greenshot/Drawing/Filters/IFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/IFilter.cs
index 37a19e73a..144732761 100644
--- a/src/Greenshot/Drawing/Filters/IFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/IFilter.cs
@@ -1,35 +1,35 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System.ComponentModel;
-using System.Drawing;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Filters
-{
- public interface IFilter : INotifyPropertyChanged, IFieldHolder
- {
- DrawableContainer Parent { get; set; }
- void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode);
- DrawableContainer GetParent();
- bool Invert { get; set; }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.ComponentModel;
+using System.Drawing;
+using Greenshot.Base.Interfaces.Drawing;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ public interface IFilter : INotifyPropertyChanged, IFieldHolder
+ {
+ DrawableContainer Parent { get; set; }
+ void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode);
+ DrawableContainer GetParent();
+ bool Invert { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/MagnifierFilter.cs b/src/Greenshot.Editor/Drawing/Filters/MagnifierFilter.cs
similarity index 95%
rename from src/Greenshot/Drawing/Filters/MagnifierFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/MagnifierFilter.cs
index 6f0bf96c4..f76640820 100644
--- a/src/Greenshot/Drawing/Filters/MagnifierFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/MagnifierFilter.cs
@@ -1,70 +1,70 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using Greenshot.Drawing.Fields;
-using System.Drawing.Drawing2D;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing.Filters
-{
- [Serializable]
- public class MagnifierFilter : AbstractFilter
- {
- public MagnifierFilter(DrawableContainer parent) : base(parent)
- {
- AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2);
- }
-
- public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
- {
- Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
-
- if (applyRect.Width == 0 || applyRect.Height == 0)
- {
- // nothing to do
- return;
- }
-
- int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR);
- GraphicsState state = graphics.Save();
- if (Invert)
- {
- graphics.SetClip(applyRect);
- graphics.ExcludeClip(rect);
- }
-
- graphics.SmoothingMode = SmoothingMode.None;
- graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
- int halfWidth = rect.Width / 2;
- int halfHeight = rect.Height / 2;
- int newWidth = rect.Width / magnificationFactor;
- int newHeight = rect.Height / magnificationFactor;
- Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight);
- graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel);
- graphics.Restore(state);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ [Serializable]
+ public class MagnifierFilter : AbstractFilter
+ {
+ public MagnifierFilter(DrawableContainer parent) : base(parent)
+ {
+ AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2);
+ }
+
+ public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
+ {
+ Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
+
+ if (applyRect.Width == 0 || applyRect.Height == 0)
+ {
+ // nothing to do
+ return;
+ }
+
+ int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR);
+ GraphicsState state = graphics.Save();
+ if (Invert)
+ {
+ graphics.SetClip(applyRect);
+ graphics.ExcludeClip(rect);
+ }
+
+ graphics.SmoothingMode = SmoothingMode.None;
+ graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+ int halfWidth = rect.Width / 2;
+ int halfHeight = rect.Height / 2;
+ int newWidth = rect.Width / magnificationFactor;
+ int newHeight = rect.Height / magnificationFactor;
+ Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight);
+ graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel);
+ graphics.Restore(state);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Filters/PixelizationFilter.cs b/src/Greenshot.Editor/Drawing/Filters/PixelizationFilter.cs
similarity index 95%
rename from src/Greenshot/Drawing/Filters/PixelizationFilter.cs
rename to src/Greenshot.Editor/Drawing/Filters/PixelizationFilter.cs
index 7440b54a6..d0b88d4f7 100644
--- a/src/Greenshot/Drawing/Filters/PixelizationFilter.cs
+++ b/src/Greenshot.Editor/Drawing/Filters/PixelizationFilter.cs
@@ -1,105 +1,105 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-
-namespace Greenshot.Drawing.Filters
-{
- [Serializable()]
- public class PixelizationFilter : AbstractFilter
- {
- public PixelizationFilter(DrawableContainer parent) : base(parent)
- {
- AddField(GetType(), FieldType.PIXEL_SIZE, 5);
- }
-
- public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
- {
- int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE);
- ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
- if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0)
- {
- // Nothing to do
- return;
- }
-
- if (rect.Width < pixelSize)
- {
- pixelSize = rect.Width;
- }
-
- if (rect.Height < pixelSize)
- {
- pixelSize = rect.Height;
- }
-
- using IFastBitmap dest = FastBitmap.CreateCloneOf(applyBitmap, rect);
- using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect))
- {
- List colors = new List();
- int halbPixelSize = pixelSize / 2;
- for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y += pixelSize)
- {
- for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x += pixelSize)
- {
- colors.Clear();
- for (int yy = y; yy < y + pixelSize; yy++)
- {
- if (yy >= src.Top && yy < src.Bottom)
- {
- for (int xx = x; xx < x + pixelSize; xx++)
- {
- if (xx >= src.Left && xx < src.Right)
- {
- colors.Add(src.GetColorAt(xx, yy));
- }
- }
- }
- }
-
- Color currentAvgColor = Colors.Mix(colors);
- for (int yy = y; yy <= y + pixelSize; yy++)
- {
- if (yy >= src.Top && yy < src.Bottom)
- {
- for (int xx = x; xx <= x + pixelSize; xx++)
- {
- if (xx >= src.Left && xx < src.Right)
- {
- dest.SetColorAt(xx, yy, currentAvgColor);
- }
- }
- }
- }
- }
- }
- }
-
- dest.DrawTo(graphics, rect.Location);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing.Filters
+{
+ [Serializable()]
+ public class PixelizationFilter : AbstractFilter
+ {
+ public PixelizationFilter(DrawableContainer parent) : base(parent)
+ {
+ AddField(GetType(), FieldType.PIXEL_SIZE, 5);
+ }
+
+ public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode)
+ {
+ int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE);
+ ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
+ if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0)
+ {
+ // Nothing to do
+ return;
+ }
+
+ if (rect.Width < pixelSize)
+ {
+ pixelSize = rect.Width;
+ }
+
+ if (rect.Height < pixelSize)
+ {
+ pixelSize = rect.Height;
+ }
+
+ using IFastBitmap dest = FastBitmap.CreateCloneOf(applyBitmap, rect);
+ using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect))
+ {
+ List colors = new List();
+ int halbPixelSize = pixelSize / 2;
+ for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y += pixelSize)
+ {
+ for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x += pixelSize)
+ {
+ colors.Clear();
+ for (int yy = y; yy < y + pixelSize; yy++)
+ {
+ if (yy >= src.Top && yy < src.Bottom)
+ {
+ for (int xx = x; xx < x + pixelSize; xx++)
+ {
+ if (xx >= src.Left && xx < src.Right)
+ {
+ colors.Add(src.GetColorAt(xx, yy));
+ }
+ }
+ }
+ }
+
+ Color currentAvgColor = Colors.Mix(colors);
+ for (int yy = y; yy <= y + pixelSize; yy++)
+ {
+ if (yy >= src.Top && yy < src.Bottom)
+ {
+ for (int xx = x; xx <= x + pixelSize; xx++)
+ {
+ if (xx >= src.Left && xx < src.Right)
+ {
+ dest.SetColorAt(xx, yy, currentAvgColor);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ dest.DrawTo(graphics, rect.Location);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/FreehandContainer.cs b/src/Greenshot.Editor/Drawing/FreehandContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/FreehandContainer.cs
rename to src/Greenshot.Editor/Drawing/FreehandContainer.cs
index d62a2ee10..e37221551 100644
--- a/src/Greenshot/Drawing/FreehandContainer.cs
+++ b/src/Greenshot.Editor/Drawing/FreehandContainer.cs
@@ -1,323 +1,323 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of PathContainer.
- ///
- [Serializable]
- public class FreehandContainer : DrawableContainer
- {
- private static readonly float[] PointOffset =
- {
- 0.5f, 0.25f, 0.75f
- };
-
- [NonSerialized] private GraphicsPath freehandPath = new GraphicsPath();
- private Rectangle myBounds = Rectangle.Empty;
- private Point lastMouse = Point.Empty;
- private readonly List capturePoints = new List();
- private bool isRecalculated;
-
- ///
- /// Constructor
- ///
- public FreehandContainer(Surface parent) : base(parent)
- {
- Width = parent.Image.Width;
- Height = parent.Image.Height;
- Top = 0;
- Left = 0;
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 3);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
- }
-
- public override void Transform(Matrix matrix)
- {
- Point[] points = capturePoints.ToArray();
-
- matrix.TransformPoints(points);
- capturePoints.Clear();
- capturePoints.AddRange(points);
- RecalculatePath();
- }
-
- protected override void OnDeserialized(StreamingContext context)
- {
- RecalculatePath();
- }
-
- ///
- /// This Dispose is called from the Dispose and the Destructor.
- ///
- /// When disposing==true all non-managed resources should be freed too!
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- if (disposing)
- {
- freehandPath?.Dispose();
- }
-
- freehandPath = null;
- }
-
- ///
- /// Called from Surface (the parent) when the drawing begins (mouse-down)
- ///
- /// true if the surface doesn't need to handle the event
- public override bool HandleMouseDown(int mouseX, int mouseY)
- {
- lastMouse = new Point(mouseX, mouseY);
- capturePoints.Add(lastMouse);
- return true;
- }
-
- ///
- /// Called from Surface (the parent) if a mouse move is made while drawing
- ///
- /// true if the surface doesn't need to handle the event
- public override bool HandleMouseMove(int mouseX, int mouseY)
- {
- Point previousPoint = capturePoints[capturePoints.Count - 1];
-
- if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2 * EditorConfig.FreehandSensitivity)
- {
- capturePoints.Add(new Point(mouseX, mouseY));
- }
-
- if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity)
- {
- return true;
- }
-
- //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)});
- lastMouse = new Point(mouseX, mouseY);
- freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY));
- // Only re-calculate the bounds & redraw when we added something to the path
- myBounds = Rectangle.Round(freehandPath.GetBounds());
-
- Invalidate();
- return true;
- }
-
- ///
- /// Called when the surface finishes drawing the element
- ///
- public override void HandleMouseUp(int mouseX, int mouseY)
- {
- // Make sure we don't loose the ending point
- if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity)
- {
- capturePoints.Add(new Point(mouseX, mouseY));
- }
-
- RecalculatePath();
- }
-
- ///
- /// Here we recalculate the freehand path by smoothing out the lines with Beziers.
- ///
- private void RecalculatePath()
- {
- // Store the previous path, to dispose it later when we are finished
- var previousFreehandPath = freehandPath;
- var newFreehandPath = new GraphicsPath();
-
- // Here we can put some cleanup... like losing all the uninteresting points.
- if (capturePoints.Count >= 3)
- {
- int index = 0;
- while ((capturePoints.Count - 1) % 3 != 0)
- {
- // duplicate points, first at 50% than 25% than 75%
- capturePoints.Insert((int) (capturePoints.Count * PointOffset[index]), capturePoints[(int) (capturePoints.Count * PointOffset[index++])]);
- }
-
- newFreehandPath.AddBeziers(capturePoints.ToArray());
- }
- else if (capturePoints.Count == 2)
- {
- newFreehandPath.AddLine(capturePoints[0], capturePoints[1]);
- }
-
- // Recalculate the bounds
- myBounds = Rectangle.Round(newFreehandPath.GetBounds());
-
- // assign
- isRecalculated = true;
- freehandPath = newFreehandPath;
-
- // dispose previous
- previousFreehandPath?.Dispose();
- }
-
- ///
- /// Do the drawing of the freehand "stroke"
- ///
- ///
- ///
- public override void Draw(Graphics graphics, RenderMode renderMode)
- {
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
-
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- using var pen = new Pen(lineColor)
- {
- Width = lineThickness
- };
- if (!(pen.Width > 0))
- {
- return;
- }
-
- // Make sure the lines are nicely rounded
- pen.EndCap = LineCap.Round;
- pen.StartCap = LineCap.Round;
- pen.LineJoin = LineJoin.Round;
- // Move to where we need to draw
- graphics.TranslateTransform(Left, Top);
- var currentFreehandPath = freehandPath;
- if (currentFreehandPath != null)
- {
- if (isRecalculated && Selected && renderMode == RenderMode.EDIT)
- {
- isRecalculated = false;
- DrawSelectionBorder(graphics, pen, currentFreehandPath);
- }
-
- graphics.DrawPath(pen, currentFreehandPath);
- }
-
- // Move back, otherwise everything is shifted
- graphics.TranslateTransform(-Left, -Top);
- }
-
- ///
- /// Draw a selectionborder around the freehand path
- ///
- /// Graphics
- /// Pen
- /// GraphicsPath
- protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path)
- {
- using var selectionPen = (Pen) linePen.Clone();
- using var selectionPath = (GraphicsPath) path.Clone();
- selectionPen.Width += 5;
- selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen);
- graphics.DrawPath(selectionPen, selectionPath);
- selectionPath.Widen(selectionPen);
- selectionPen.DashPattern = new float[]
- {
- 2, 2
- };
- selectionPen.Color = Color.LightSeaGreen;
- selectionPen.Width = 1;
- graphics.DrawPath(selectionPen, selectionPath);
- }
-
- ///
- /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds...
- ///
- public override Rectangle DrawingBounds
- {
- get
- {
- if (!myBounds.IsEmpty)
- {
- int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS));
- 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));
- }
-
- if (_parent?.Image is Image image)
- {
- return new Rectangle(0, 0, image.Width, image.Height);
- }
- else
- {
- return Rectangle.Empty;
- }
- }
- }
-
- ///
- /// FreehandContainer are regarded equal if they are of the same type and their paths are equal.
- ///
- /// object
- /// bool
- public override bool Equals(object obj)
- {
- bool ret = false;
- if (obj == null || GetType() != obj.GetType())
- {
- return false;
- }
-
- if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath))
- {
- ret = true;
- }
-
- return ret;
- }
-
- public override int GetHashCode()
- {
- return freehandPath?.GetHashCode() ?? 0;
- }
-
- public override bool ClickableAt(int x, int y)
- {
- bool returnValue = base.ClickableAt(x, y);
- if (returnValue)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- using var pen = new Pen(Color.White)
- {
- Width = lineThickness + 10
- };
- returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen);
- }
-
- return returnValue;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of PathContainer.
+ ///
+ [Serializable]
+ public class FreehandContainer : DrawableContainer
+ {
+ private static readonly float[] PointOffset =
+ {
+ 0.5f, 0.25f, 0.75f
+ };
+
+ [NonSerialized] private GraphicsPath freehandPath = new GraphicsPath();
+ private Rectangle myBounds = Rectangle.Empty;
+ private Point lastMouse = Point.Empty;
+ private readonly List capturePoints = new List();
+ private bool isRecalculated;
+
+ ///
+ /// Constructor
+ ///
+ public FreehandContainer(Surface parent) : base(parent)
+ {
+ Width = parent.Image.Width;
+ Height = parent.Image.Height;
+ Top = 0;
+ Left = 0;
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 3);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
+ }
+
+ public override void Transform(Matrix matrix)
+ {
+ Point[] points = capturePoints.ToArray();
+
+ matrix.TransformPoints(points);
+ capturePoints.Clear();
+ capturePoints.AddRange(points);
+ RecalculatePath();
+ }
+
+ protected override void OnDeserialized(StreamingContext context)
+ {
+ RecalculatePath();
+ }
+
+ ///
+ /// This Dispose is called from the Dispose and the Destructor.
+ ///
+ /// When disposing==true all non-managed resources should be freed too!
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (disposing)
+ {
+ freehandPath?.Dispose();
+ }
+
+ freehandPath = null;
+ }
+
+ ///
+ /// Called from Surface (the parent) when the drawing begins (mouse-down)
+ ///
+ /// true if the surface doesn't need to handle the event
+ public override bool HandleMouseDown(int mouseX, int mouseY)
+ {
+ lastMouse = new Point(mouseX, mouseY);
+ capturePoints.Add(lastMouse);
+ return true;
+ }
+
+ ///
+ /// Called from Surface (the parent) if a mouse move is made while drawing
+ ///
+ /// true if the surface doesn't need to handle the event
+ public override bool HandleMouseMove(int mouseX, int mouseY)
+ {
+ Point previousPoint = capturePoints[capturePoints.Count - 1];
+
+ if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2 * EditorConfig.FreehandSensitivity)
+ {
+ capturePoints.Add(new Point(mouseX, mouseY));
+ }
+
+ if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity)
+ {
+ return true;
+ }
+
+ //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)});
+ lastMouse = new Point(mouseX, mouseY);
+ freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY));
+ // Only re-calculate the bounds & redraw when we added something to the path
+ myBounds = Rectangle.Round(freehandPath.GetBounds());
+
+ Invalidate();
+ return true;
+ }
+
+ ///
+ /// Called when the surface finishes drawing the element
+ ///
+ public override void HandleMouseUp(int mouseX, int mouseY)
+ {
+ // Make sure we don't loose the ending point
+ if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity)
+ {
+ capturePoints.Add(new Point(mouseX, mouseY));
+ }
+
+ RecalculatePath();
+ }
+
+ ///
+ /// Here we recalculate the freehand path by smoothing out the lines with Beziers.
+ ///
+ private void RecalculatePath()
+ {
+ // Store the previous path, to dispose it later when we are finished
+ var previousFreehandPath = freehandPath;
+ var newFreehandPath = new GraphicsPath();
+
+ // Here we can put some cleanup... like losing all the uninteresting points.
+ if (capturePoints.Count >= 3)
+ {
+ int index = 0;
+ while ((capturePoints.Count - 1) % 3 != 0)
+ {
+ // duplicate points, first at 50% than 25% than 75%
+ capturePoints.Insert((int) (capturePoints.Count * PointOffset[index]), capturePoints[(int) (capturePoints.Count * PointOffset[index++])]);
+ }
+
+ newFreehandPath.AddBeziers(capturePoints.ToArray());
+ }
+ else if (capturePoints.Count == 2)
+ {
+ newFreehandPath.AddLine(capturePoints[0], capturePoints[1]);
+ }
+
+ // Recalculate the bounds
+ myBounds = Rectangle.Round(newFreehandPath.GetBounds());
+
+ // assign
+ isRecalculated = true;
+ freehandPath = newFreehandPath;
+
+ // dispose previous
+ previousFreehandPath?.Dispose();
+ }
+
+ ///
+ /// Do the drawing of the freehand "stroke"
+ ///
+ ///
+ ///
+ public override void Draw(Graphics graphics, RenderMode renderMode)
+ {
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ using var pen = new Pen(lineColor)
+ {
+ Width = lineThickness
+ };
+ if (!(pen.Width > 0))
+ {
+ return;
+ }
+
+ // Make sure the lines are nicely rounded
+ pen.EndCap = LineCap.Round;
+ pen.StartCap = LineCap.Round;
+ pen.LineJoin = LineJoin.Round;
+ // Move to where we need to draw
+ graphics.TranslateTransform(Left, Top);
+ var currentFreehandPath = freehandPath;
+ if (currentFreehandPath != null)
+ {
+ if (isRecalculated && Selected && renderMode == RenderMode.EDIT)
+ {
+ isRecalculated = false;
+ DrawSelectionBorder(graphics, pen, currentFreehandPath);
+ }
+
+ graphics.DrawPath(pen, currentFreehandPath);
+ }
+
+ // Move back, otherwise everything is shifted
+ graphics.TranslateTransform(-Left, -Top);
+ }
+
+ ///
+ /// Draw a selectionborder around the freehand path
+ ///
+ /// Graphics
+ /// Pen
+ /// GraphicsPath
+ protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path)
+ {
+ using var selectionPen = (Pen) linePen.Clone();
+ using var selectionPath = (GraphicsPath) path.Clone();
+ selectionPen.Width += 5;
+ selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen);
+ graphics.DrawPath(selectionPen, selectionPath);
+ selectionPath.Widen(selectionPen);
+ selectionPen.DashPattern = new float[]
+ {
+ 2, 2
+ };
+ selectionPen.Color = Color.LightSeaGreen;
+ selectionPen.Width = 1;
+ graphics.DrawPath(selectionPen, selectionPath);
+ }
+
+ ///
+ /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds...
+ ///
+ public override Rectangle DrawingBounds
+ {
+ get
+ {
+ if (!myBounds.IsEmpty)
+ {
+ int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS));
+ 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));
+ }
+
+ if (_parent?.Image is Image image)
+ {
+ return new Rectangle(0, 0, image.Width, image.Height);
+ }
+ else
+ {
+ return Rectangle.Empty;
+ }
+ }
+ }
+
+ ///
+ /// FreehandContainer are regarded equal if they are of the same type and their paths are equal.
+ ///
+ /// object
+ /// bool
+ public override bool Equals(object obj)
+ {
+ bool ret = false;
+ if (obj == null || GetType() != obj.GetType())
+ {
+ return false;
+ }
+
+ if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath))
+ {
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ public override int GetHashCode()
+ {
+ return freehandPath?.GetHashCode() ?? 0;
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ bool returnValue = base.ClickableAt(x, y);
+ if (returnValue)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ using var pen = new Pen(Color.White)
+ {
+ Width = lineThickness + 10
+ };
+ returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen);
+ }
+
+ return returnValue;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/HighlightContainer.cs b/src/Greenshot.Editor/Drawing/HighlightContainer.cs
similarity index 94%
rename from src/Greenshot/Drawing/HighlightContainer.cs
rename to src/Greenshot.Editor/Drawing/HighlightContainer.cs
index c9b502f06..3e104b85f 100644
--- a/src/Greenshot/Drawing/HighlightContainer.cs
+++ b/src/Greenshot.Editor/Drawing/HighlightContainer.cs
@@ -1,112 +1,112 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-using Greenshot.Drawing.Filters;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of ObfuscateContainer.
- ///
- [Serializable]
- public class HighlightContainer : FilterContainer
- {
- public HighlightContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- ///
- /// Use settings from base, extend with our own field
- ///
- protected override void InitializeFields()
- {
- base.InitializeFields();
- AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT);
- }
-
- protected override void OnDeserialized(StreamingContext context)
- {
- Init();
- }
-
- private void Init()
- {
- FieldChanged += HighlightContainer_OnFieldChanged;
- ConfigurePreparedFilters();
- }
-
- protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e)
- {
- if (!sender.Equals(this))
- {
- return;
- }
-
- if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_HIGHLIGHT))
- {
- ConfigurePreparedFilters();
- }
- }
-
- private void ConfigurePreparedFilters()
- {
- PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT);
- while (Filters.Count > 0)
- {
- Remove(Filters[0]);
- }
-
- switch (preset)
- {
- case PreparedFilter.TEXT_HIGHTLIGHT:
- Add(new HighlightFilter(this));
- break;
- case PreparedFilter.AREA_HIGHLIGHT:
- var brightnessFilter = new BrightnessFilter(this)
- {
- Invert = true
- };
- Add(brightnessFilter);
- var blurFilter = new BlurFilter(this)
- {
- Invert = true
- };
- Add(blurFilter);
- break;
- case PreparedFilter.GRAYSCALE:
- AbstractFilter f = new GrayscaleFilter(this)
- {
- Invert = true
- };
- Add(f);
- break;
- case PreparedFilter.MAGNIFICATION:
- Add(new MagnifierFilter(this));
- break;
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Drawing.Filters;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of ObfuscateContainer.
+ ///
+ [Serializable]
+ public class HighlightContainer : FilterContainer
+ {
+ public HighlightContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ ///
+ /// Use settings from base, extend with our own field
+ ///
+ protected override void InitializeFields()
+ {
+ base.InitializeFields();
+ AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT);
+ }
+
+ protected override void OnDeserialized(StreamingContext context)
+ {
+ Init();
+ }
+
+ private void Init()
+ {
+ FieldChanged += HighlightContainer_OnFieldChanged;
+ ConfigurePreparedFilters();
+ }
+
+ protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ if (!sender.Equals(this))
+ {
+ return;
+ }
+
+ if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_HIGHLIGHT))
+ {
+ ConfigurePreparedFilters();
+ }
+ }
+
+ private void ConfigurePreparedFilters()
+ {
+ PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT);
+ while (Filters.Count > 0)
+ {
+ Remove(Filters[0]);
+ }
+
+ switch (preset)
+ {
+ case PreparedFilter.TEXT_HIGHTLIGHT:
+ Add(new HighlightFilter(this));
+ break;
+ case PreparedFilter.AREA_HIGHLIGHT:
+ var brightnessFilter = new BrightnessFilter(this)
+ {
+ Invert = true
+ };
+ Add(brightnessFilter);
+ var blurFilter = new BlurFilter(this)
+ {
+ Invert = true
+ };
+ Add(blurFilter);
+ break;
+ case PreparedFilter.GRAYSCALE:
+ AbstractFilter f = new GrayscaleFilter(this)
+ {
+ Invert = true
+ };
+ Add(f);
+ break;
+ case PreparedFilter.MAGNIFICATION:
+ Add(new MagnifierFilter(this));
+ break;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/IconContainer.cs b/src/Greenshot.Editor/Drawing/IconContainer.cs
similarity index 95%
rename from src/Greenshot/Drawing/IconContainer.cs
rename to src/Greenshot.Editor/Drawing/IconContainer.cs
index 766126219..e98b37f82 100644
--- a/src/Greenshot/Drawing/IconContainer.cs
+++ b/src/Greenshot.Editor/Drawing/IconContainer.cs
@@ -1,120 +1,120 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.IO;
-using System.Drawing.Drawing2D;
-using log4net;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of IconContainer.
- ///
- [Serializable]
- public class IconContainer : DrawableContainer, IIconContainer
- {
- private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer));
-
- protected Icon icon;
-
- public IconContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- Init();
- }
-
- private void Init()
- {
- CreateDefaultAdorners();
- }
-
- public IconContainer(Surface parent, string filename) : base(parent)
- {
- Load(filename);
- }
-
- public Icon Icon
- {
- set
- {
- icon?.Dispose();
- icon = (Icon) value.Clone();
- Width = value.Width;
- Height = value.Height;
- }
- get => icon;
- }
-
- /**
- * This Dispose is called from the Dispose and the Destructor.
- * When disposing==true all non-managed resources should be freed too!
- */
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- icon?.Dispose();
- }
-
- icon = null;
- base.Dispose(disposing);
- }
-
- public void Load(string filename)
- {
- if (!File.Exists(filename))
- {
- return;
- }
-
- using Icon fileIcon = new Icon(filename);
- Icon = fileIcon;
- Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
- }
-
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- if (icon == null)
- {
- return;
- }
-
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
- graphics.CompositingQuality = CompositingQuality.Default;
- graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
- graphics.DrawIcon(icon, Bounds);
- }
-
- public override bool HasDefaultSize => true;
-
- public override Size DefaultSize => icon?.Size ?? new Size(16, 16);
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.IO;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using log4net;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of IconContainer.
+ ///
+ [Serializable]
+ public class IconContainer : DrawableContainer, IIconContainer
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer));
+
+ protected Icon icon;
+
+ public IconContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ Init();
+ }
+
+ private void Init()
+ {
+ CreateDefaultAdorners();
+ }
+
+ public IconContainer(Surface parent, string filename) : base(parent)
+ {
+ Load(filename);
+ }
+
+ public Icon Icon
+ {
+ set
+ {
+ icon?.Dispose();
+ icon = (Icon) value.Clone();
+ Width = value.Width;
+ Height = value.Height;
+ }
+ get => icon;
+ }
+
+ /**
+ * This Dispose is called from the Dispose and the Destructor.
+ * When disposing==true all non-managed resources should be freed too!
+ */
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ icon?.Dispose();
+ }
+
+ icon = null;
+ base.Dispose(disposing);
+ }
+
+ public void Load(string filename)
+ {
+ if (!File.Exists(filename))
+ {
+ return;
+ }
+
+ using Icon fileIcon = new Icon(filename);
+ Icon = fileIcon;
+ Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
+ }
+
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ if (icon == null)
+ {
+ return;
+ }
+
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
+ graphics.CompositingQuality = CompositingQuality.Default;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ graphics.DrawIcon(icon, Bounds);
+ }
+
+ public override bool HasDefaultSize => true;
+
+ public override Size DefaultSize => icon?.Size ?? new Size(16, 16);
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/ImageContainer.cs b/src/Greenshot.Editor/Drawing/ImageContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/ImageContainer.cs
rename to src/Greenshot.Editor/Drawing/ImageContainer.cs
index 631fe56ce..a46b0dae5 100644
--- a/src/Greenshot/Drawing/ImageContainer.cs
+++ b/src/Greenshot.Editor/Drawing/ImageContainer.cs
@@ -1,267 +1,267 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.IO;
-using Greenshot.Drawing.Fields;
-using System.Drawing.Drawing2D;
-using log4net;
-using System.Runtime.Serialization;
-using Greenshot.Base.Core;
-using Greenshot.Base.Effects;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of BitmapContainer.
- ///
- [Serializable]
- public class ImageContainer : DrawableContainer, IImageContainer
- {
- private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer));
-
- private Image image;
-
- ///
- /// This is the shadow version of the bitmap, rendered once to save performance
- /// Do not serialize, as the shadow is recreated from the original bitmap if it's not available
- ///
- [NonSerialized] private Image _shadowBitmap;
-
- ///
- /// This is the offset for the shadow version of the bitmap
- /// Do not serialize, as the offset is recreated
- ///
- [NonSerialized] private Point _shadowOffset = new Point(-1, -1);
-
- public ImageContainer(Surface parent, string filename) : this(parent)
- {
- Load(filename);
- }
-
- public ImageContainer(Surface parent) : base(parent)
- {
- FieldChanged += BitmapContainer_OnFieldChanged;
- Init();
- }
-
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- Init();
- }
-
- private void Init()
- {
- CreateDefaultAdorners();
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.SHADOW, false);
- }
-
- protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e)
- {
- if (!sender.Equals(this))
- {
- return;
- }
-
- if (FieldType.SHADOW.Equals(e.Field.FieldType))
- {
- ChangeShadowField();
- }
- }
-
- public void ChangeShadowField()
- {
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- if (shadow)
- {
- CheckShadow(true);
- Width = _shadowBitmap.Width;
- Height = _shadowBitmap.Height;
- Left -= _shadowOffset.X;
- Top -= _shadowOffset.Y;
- }
- else
- {
- Width = image.Width;
- Height = image.Height;
- if (_shadowBitmap != null)
- {
- Left += _shadowOffset.X;
- Top += _shadowOffset.Y;
- }
- }
- }
-
- public Image Image
- {
- set
- {
- // Remove all current bitmaps
- DisposeImage();
- DisposeShadow();
- image = ImageHelper.Clone(value);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- CheckShadow(shadow);
- if (!shadow)
- {
- Width = image.Width;
- Height = image.Height;
- }
- else
- {
- Width = _shadowBitmap.Width;
- Height = _shadowBitmap.Height;
- Left -= _shadowOffset.X;
- Top -= _shadowOffset.Y;
- }
- }
- get { return image; }
- }
-
- ///
- /// The bulk of the clean-up code is implemented in Dispose(bool)
- /// This Dispose is called from the Dispose and the Destructor.
- /// When disposing==true all non-managed resources should be freed too!
- ///
- ///
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- DisposeImage();
- DisposeShadow();
- }
-
- base.Dispose(disposing);
- }
-
- private void DisposeImage()
- {
- image?.Dispose();
- image = null;
- }
-
- private void DisposeShadow()
- {
- _shadowBitmap?.Dispose();
- _shadowBitmap = null;
- }
-
-
- ///
- /// Make sure the content is also transformed.
- ///
- ///
- public override void Transform(Matrix matrix)
- {
- int rotateAngle = CalculateAngle(matrix);
- // we currently assume only one transformation has been made.
- if (rotateAngle != 0)
- {
- Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle);
- DisposeShadow();
- using var tmpMatrix = new Matrix();
- using (image)
- {
- image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix);
- }
- }
-
- base.Transform(matrix);
- }
-
- ///
- ///
- ///
- ///
- public void Load(string filename)
- {
- if (!File.Exists(filename))
- {
- return;
- }
-
- // Always make sure ImageHelper.LoadBitmap results are disposed some time,
- // as we close the bitmap internally, we need to do it afterwards
- using (var tmpImage = ImageHelper.LoadImage(filename))
- {
- Image = tmpImage;
- }
-
- Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
- }
-
- ///
- /// This checks if a shadow is already generated
- ///
- ///
- private void CheckShadow(bool shadow)
- {
- if (!shadow || _shadowBitmap != null)
- {
- return;
- }
-
- using var matrix = new Matrix();
- _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix);
- }
-
- ///
- /// Draw the actual container to the graphics object
- ///
- ///
- ///
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- if (image == null)
- {
- return;
- }
-
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
-
- if (shadow)
- {
- CheckShadow(true);
- graphics.DrawImage(_shadowBitmap, Bounds);
- }
- else
- {
- graphics.DrawImage(image, Bounds);
- }
- }
-
- public override bool HasDefaultSize => true;
-
- public override Size DefaultSize => image?.Size ?? new Size(32, 32);
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.IO;
+using System.Runtime.Serialization;
+using Greenshot.Base.Core;
+using Greenshot.Base.Effects;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using log4net;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of BitmapContainer.
+ ///
+ [Serializable]
+ public class ImageContainer : DrawableContainer, IImageContainer
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer));
+
+ private Image image;
+
+ ///
+ /// This is the shadow version of the bitmap, rendered once to save performance
+ /// Do not serialize, as the shadow is recreated from the original bitmap if it's not available
+ ///
+ [NonSerialized] private Image _shadowBitmap;
+
+ ///
+ /// This is the offset for the shadow version of the bitmap
+ /// Do not serialize, as the offset is recreated
+ ///
+ [NonSerialized] private Point _shadowOffset = new Point(-1, -1);
+
+ public ImageContainer(Surface parent, string filename) : this(parent)
+ {
+ Load(filename);
+ }
+
+ public ImageContainer(Surface parent) : base(parent)
+ {
+ FieldChanged += BitmapContainer_OnFieldChanged;
+ Init();
+ }
+
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ Init();
+ }
+
+ private void Init()
+ {
+ CreateDefaultAdorners();
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.SHADOW, false);
+ }
+
+ protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ if (!sender.Equals(this))
+ {
+ return;
+ }
+
+ if (FieldType.SHADOW.Equals(e.Field.FieldType))
+ {
+ ChangeShadowField();
+ }
+ }
+
+ public void ChangeShadowField()
+ {
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ if (shadow)
+ {
+ CheckShadow(true);
+ Width = _shadowBitmap.Width;
+ Height = _shadowBitmap.Height;
+ Left -= _shadowOffset.X;
+ Top -= _shadowOffset.Y;
+ }
+ else
+ {
+ Width = image.Width;
+ Height = image.Height;
+ if (_shadowBitmap != null)
+ {
+ Left += _shadowOffset.X;
+ Top += _shadowOffset.Y;
+ }
+ }
+ }
+
+ public Image Image
+ {
+ set
+ {
+ // Remove all current bitmaps
+ DisposeImage();
+ DisposeShadow();
+ image = ImageHelper.Clone(value);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ CheckShadow(shadow);
+ if (!shadow)
+ {
+ Width = image.Width;
+ Height = image.Height;
+ }
+ else
+ {
+ Width = _shadowBitmap.Width;
+ Height = _shadowBitmap.Height;
+ Left -= _shadowOffset.X;
+ Top -= _shadowOffset.Y;
+ }
+ }
+ get { return image; }
+ }
+
+ ///
+ /// The bulk of the clean-up code is implemented in Dispose(bool)
+ /// This Dispose is called from the Dispose and the Destructor.
+ /// When disposing==true all non-managed resources should be freed too!
+ ///
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ DisposeImage();
+ DisposeShadow();
+ }
+
+ base.Dispose(disposing);
+ }
+
+ private void DisposeImage()
+ {
+ image?.Dispose();
+ image = null;
+ }
+
+ private void DisposeShadow()
+ {
+ _shadowBitmap?.Dispose();
+ _shadowBitmap = null;
+ }
+
+
+ ///
+ /// Make sure the content is also transformed.
+ ///
+ ///
+ public override void Transform(Matrix matrix)
+ {
+ int rotateAngle = CalculateAngle(matrix);
+ // we currently assume only one transformation has been made.
+ if (rotateAngle != 0)
+ {
+ Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle);
+ DisposeShadow();
+ using var tmpMatrix = new Matrix();
+ using (image)
+ {
+ image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix);
+ }
+ }
+
+ base.Transform(matrix);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public void Load(string filename)
+ {
+ if (!File.Exists(filename))
+ {
+ return;
+ }
+
+ // Always make sure ImageHelper.LoadBitmap results are disposed some time,
+ // as we close the bitmap internally, we need to do it afterwards
+ using (var tmpImage = ImageHelper.LoadImage(filename))
+ {
+ Image = tmpImage;
+ }
+
+ Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
+ }
+
+ ///
+ /// This checks if a shadow is already generated
+ ///
+ ///
+ private void CheckShadow(bool shadow)
+ {
+ if (!shadow || _shadowBitmap != null)
+ {
+ return;
+ }
+
+ using var matrix = new Matrix();
+ _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix);
+ }
+
+ ///
+ /// Draw the actual container to the graphics object
+ ///
+ ///
+ ///
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ if (image == null)
+ {
+ return;
+ }
+
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+
+ if (shadow)
+ {
+ CheckShadow(true);
+ graphics.DrawImage(_shadowBitmap, Bounds);
+ }
+ else
+ {
+ graphics.DrawImage(image, Bounds);
+ }
+ }
+
+ public override bool HasDefaultSize => true;
+
+ public override Size DefaultSize => image?.Size ?? new Size(32, 32);
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/LineContainer.cs b/src/Greenshot.Editor/Drawing/LineContainer.cs
similarity index 94%
rename from src/Greenshot/Drawing/LineContainer.cs
rename to src/Greenshot.Editor/Drawing/LineContainer.cs
index 4f74f295d..1bcf25a81 100644
--- a/src/Greenshot/Drawing/LineContainer.cs
+++ b/src/Greenshot.Editor/Drawing/LineContainer.cs
@@ -1,123 +1,123 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using Greenshot.Drawing.Adorners;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of LineContainer.
- ///
- [Serializable()]
- public class LineContainer : DrawableContainer
- {
- public LineContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 2);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
- AddField(GetType(), FieldType.SHADOW, true);
- }
-
- protected override void OnDeserialized(StreamingContext context)
- {
- Init();
- }
-
- protected void Init()
- {
- Adorners.Add(new MoveAdorner(this, Positions.TopLeft));
- Adorners.Add(new MoveAdorner(this, Positions.BottomRight));
- }
-
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
-
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
-
- if (lineThickness > 0)
- {
- if (shadow)
- {
- //draw shadow first
- int basealpha = 100;
- int alpha = basealpha;
- int steps = 5;
- int currentStep = 1;
- while (currentStep <= steps)
- {
- using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
- graphics.DrawLine(shadowCapPen,
- Left + currentStep,
- Top + currentStep,
- Left + currentStep + Width,
- Top + currentStep + Height);
-
- currentStep++;
- alpha -= basealpha / steps;
- }
- }
-
- using Pen pen = new Pen(lineColor, lineThickness);
- graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height);
- }
- }
-
- public override bool ClickableAt(int x, int y)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 5;
- if (lineThickness > 0)
- {
- using Pen pen = new Pen(Color.White)
- {
- Width = lineThickness
- };
- using GraphicsPath path = new GraphicsPath();
- path.AddLine(Left, Top, Left + Width, Top + Height);
- return path.IsOutlineVisible(x, y, pen);
- }
-
- return false;
- }
-
- protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor()
- {
- return ScaleHelper.LineAngleRoundBehavior.Instance;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Adorners;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of LineContainer.
+ ///
+ [Serializable()]
+ public class LineContainer : DrawableContainer
+ {
+ public LineContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 2);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
+ AddField(GetType(), FieldType.SHADOW, true);
+ }
+
+ protected override void OnDeserialized(StreamingContext context)
+ {
+ Init();
+ }
+
+ protected void Init()
+ {
+ Adorners.Add(new MoveAdorner(this, Positions.TopLeft));
+ Adorners.Add(new MoveAdorner(this, Positions.BottomRight));
+ }
+
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+
+ if (lineThickness > 0)
+ {
+ if (shadow)
+ {
+ //draw shadow first
+ int basealpha = 100;
+ int alpha = basealpha;
+ int steps = 5;
+ int currentStep = 1;
+ while (currentStep <= steps)
+ {
+ using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
+ graphics.DrawLine(shadowCapPen,
+ Left + currentStep,
+ Top + currentStep,
+ Left + currentStep + Width,
+ Top + currentStep + Height);
+
+ currentStep++;
+ alpha -= basealpha / steps;
+ }
+ }
+
+ using Pen pen = new Pen(lineColor, lineThickness);
+ graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height);
+ }
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 5;
+ if (lineThickness > 0)
+ {
+ using Pen pen = new Pen(Color.White)
+ {
+ Width = lineThickness
+ };
+ using GraphicsPath path = new GraphicsPath();
+ path.AddLine(Left, Top, Left + Width, Top + Height);
+ return path.IsOutlineVisible(x, y, pen);
+ }
+
+ return false;
+ }
+
+ protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor()
+ {
+ return ScaleHelper.LineAngleRoundBehavior.Instance;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/ObfuscateContainer.cs b/src/Greenshot.Editor/Drawing/ObfuscateContainer.cs
similarity index 93%
rename from src/Greenshot/Drawing/ObfuscateContainer.cs
rename to src/Greenshot.Editor/Drawing/ObfuscateContainer.cs
index 9709dffde..1754ba650 100644
--- a/src/Greenshot/Drawing/ObfuscateContainer.cs
+++ b/src/Greenshot.Editor/Drawing/ObfuscateContainer.cs
@@ -1,89 +1,89 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Drawing.Fields;
-using Greenshot.Drawing.Filters;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of ObfuscateContainer.
- ///
- [Serializable]
- public class ObfuscateContainer : FilterContainer
- {
- public ObfuscateContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- protected override void InitializeFields()
- {
- base.InitializeFields();
- AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE);
- }
-
- protected override void OnDeserialized(StreamingContext context)
- {
- Init();
- }
-
- private void Init()
- {
- FieldChanged += ObfuscateContainer_OnFieldChanged;
- ConfigurePreparedFilters();
- CreateDefaultAdorners();
- }
-
- protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e)
- {
- if (sender.Equals(this))
- {
- if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_OBFUSCATE))
- {
- ConfigurePreparedFilters();
- }
- }
- }
-
- private void ConfigurePreparedFilters()
- {
- PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE);
- while (Filters.Count > 0)
- {
- Remove(Filters[0]);
- }
-
- switch (preset)
- {
- case PreparedFilter.BLUR:
- Add(new BlurFilter(this));
- break;
- case PreparedFilter.PIXELIZE:
- Add(new PixelizationFilter(this));
- break;
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Drawing.Filters;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of ObfuscateContainer.
+ ///
+ [Serializable]
+ public class ObfuscateContainer : FilterContainer
+ {
+ public ObfuscateContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ protected override void InitializeFields()
+ {
+ base.InitializeFields();
+ AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE);
+ }
+
+ protected override void OnDeserialized(StreamingContext context)
+ {
+ Init();
+ }
+
+ private void Init()
+ {
+ FieldChanged += ObfuscateContainer_OnFieldChanged;
+ ConfigurePreparedFilters();
+ CreateDefaultAdorners();
+ }
+
+ protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ if (sender.Equals(this))
+ {
+ if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_OBFUSCATE))
+ {
+ ConfigurePreparedFilters();
+ }
+ }
+ }
+
+ private void ConfigurePreparedFilters()
+ {
+ PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE);
+ while (Filters.Count > 0)
+ {
+ Remove(Filters[0]);
+ }
+
+ switch (preset)
+ {
+ case PreparedFilter.BLUR:
+ Add(new BlurFilter(this));
+ break;
+ case PreparedFilter.PIXELIZE:
+ Add(new PixelizationFilter(this));
+ break;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Positions.cs b/src/Greenshot.Editor/Drawing/Positions.cs
similarity index 94%
rename from src/Greenshot/Drawing/Positions.cs
rename to src/Greenshot.Editor/Drawing/Positions.cs
index 0b3f391ec..863690887 100644
--- a/src/Greenshot/Drawing/Positions.cs
+++ b/src/Greenshot.Editor/Drawing/Positions.cs
@@ -1,38 +1,38 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-namespace Greenshot.Drawing
-{
- ///
- /// Position
- ///
- public enum Positions : int
- {
- TopLeft = 0,
- TopCenter = 1,
- TopRight = 2,
- MiddleRight = 3,
- BottomRight = 4,
- BottomCenter = 5,
- BottomLeft = 6,
- MiddleLeft = 7
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Position
+ ///
+ public enum Positions : int
+ {
+ TopLeft = 0,
+ TopCenter = 1,
+ TopRight = 2,
+ MiddleRight = 3,
+ BottomRight = 4,
+ BottomCenter = 5,
+ BottomLeft = 6,
+ MiddleLeft = 7
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/RectangleContainer.cs b/src/Greenshot.Editor/Drawing/RectangleContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/RectangleContainer.cs
rename to src/Greenshot.Editor/Drawing/RectangleContainer.cs
index 778451d2b..5e38fcf4b 100644
--- a/src/Greenshot/Drawing/RectangleContainer.cs
+++ b/src/Greenshot.Editor/Drawing/RectangleContainer.cs
@@ -1,167 +1,167 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Represents a rectangular shape on the Surface
- ///
- [Serializable]
- public class RectangleContainer : DrawableContainer
- {
- public RectangleContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- ///
- /// Do some logic to make sure all field are initiated correctly
- ///
- /// StreamingContext
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- Init();
- }
-
- private void Init()
- {
- CreateDefaultAdorners();
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 2);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
- AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
- AddField(GetType(), FieldType.SHADOW, true);
- }
-
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red);
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
-
- DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow);
- }
-
- ///
- /// This method can also be used from other containers, if the right values are passed!
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow)
- {
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
-
- bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
- if (shadow && (lineVisible || Colors.IsVisible(fillColor)))
- {
- //draw shadow first
- int basealpha = 100;
- int alpha = basealpha;
- int steps = 5;
- int currentStep = lineVisible ? 1 : 0;
- while (currentStep <= steps)
- {
- using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))
- {
- Width = lineVisible ? lineThickness : 1
- };
- Rectangle shadowRect = GuiRectangle.GetGuiRectangle(
- rect.Left + currentStep,
- rect.Top + currentStep,
- rect.Width,
- rect.Height);
- graphics.DrawRectangle(shadowPen, shadowRect);
- currentStep++;
- alpha -= basealpha / steps;
- }
- }
-
-
- if (Colors.IsVisible(fillColor))
- {
- using Brush brush = new SolidBrush(fillColor);
- graphics.FillRectangle(brush, rect);
- }
-
- graphics.SmoothingMode = SmoothingMode.HighSpeed;
- if (lineVisible)
- {
- using Pen pen = new Pen(lineColor, lineThickness);
- graphics.DrawRectangle(pen, rect);
- }
- }
-
- public override bool ClickableAt(int x, int y)
- {
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
-
- return RectangleClickableAt(rect, lineThickness, fillColor, x, y);
- }
-
-
- public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y)
- {
- // If we clicked inside the rectangle and it's visible we are clickable at.
- if (!Color.Transparent.Equals(fillColor))
- {
- if (rect.Contains(x, y))
- {
- return true;
- }
- }
-
- // check the rest of the lines
- if (lineThickness > 0)
- {
- using Pen pen = new Pen(Color.White, lineThickness);
- using GraphicsPath path = new GraphicsPath();
- path.AddRectangle(rect);
- return path.IsOutlineVisible(x, y, pen);
- }
-
- return false;
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Represents a rectangular shape on the Surface
+ ///
+ [Serializable]
+ public class RectangleContainer : DrawableContainer
+ {
+ public RectangleContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ ///
+ /// Do some logic to make sure all field are initiated correctly
+ ///
+ /// StreamingContext
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ Init();
+ }
+
+ private void Init()
+ {
+ CreateDefaultAdorners();
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 2);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
+ AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
+ AddField(GetType(), FieldType.SHADOW, true);
+ }
+
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red);
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+
+ DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow);
+ }
+
+ ///
+ /// This method can also be used from other containers, if the right values are passed!
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow)
+ {
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+
+ bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
+ if (shadow && (lineVisible || Colors.IsVisible(fillColor)))
+ {
+ //draw shadow first
+ int basealpha = 100;
+ int alpha = basealpha;
+ int steps = 5;
+ int currentStep = lineVisible ? 1 : 0;
+ while (currentStep <= steps)
+ {
+ using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))
+ {
+ Width = lineVisible ? lineThickness : 1
+ };
+ Rectangle shadowRect = GuiRectangle.GetGuiRectangle(
+ rect.Left + currentStep,
+ rect.Top + currentStep,
+ rect.Width,
+ rect.Height);
+ graphics.DrawRectangle(shadowPen, shadowRect);
+ currentStep++;
+ alpha -= basealpha / steps;
+ }
+ }
+
+
+ if (Colors.IsVisible(fillColor))
+ {
+ using Brush brush = new SolidBrush(fillColor);
+ graphics.FillRectangle(brush, rect);
+ }
+
+ graphics.SmoothingMode = SmoothingMode.HighSpeed;
+ if (lineVisible)
+ {
+ using Pen pen = new Pen(lineColor, lineThickness);
+ graphics.DrawRectangle(pen, rect);
+ }
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10;
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+
+ return RectangleClickableAt(rect, lineThickness, fillColor, x, y);
+ }
+
+
+ public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y)
+ {
+ // If we clicked inside the rectangle and it's visible we are clickable at.
+ if (!Color.Transparent.Equals(fillColor))
+ {
+ if (rect.Contains(x, y))
+ {
+ return true;
+ }
+ }
+
+ // check the rest of the lines
+ if (lineThickness > 0)
+ {
+ using Pen pen = new Pen(Color.White, lineThickness);
+ using GraphicsPath path = new GraphicsPath();
+ path.AddRectangle(rect);
+ return path.IsOutlineVisible(x, y, pen);
+ }
+
+ return false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/SpeechbubbleContainer.cs b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/SpeechbubbleContainer.cs
rename to src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs
index d54c98ec4..2b189945d 100644
--- a/src/Greenshot/Drawing/SpeechbubbleContainer.cs
+++ b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs
@@ -1,399 +1,399 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Text;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of SpeechbubbleContainer.
- ///
- [Serializable]
- public class SpeechbubbleContainer : TextContainer
- {
- private Point _initialGripperPoint;
-
- // Only used for serializing the TargetGripper location
- private Point _storedTargetGripperLocation;
-
- ///
- /// Store the current location of the target gripper
- ///
- ///
- [OnSerializing]
- private void SetValuesOnSerializing(StreamingContext context)
- {
- if (TargetAdorner != null)
- {
- _storedTargetGripperLocation = TargetAdorner.Location;
- }
- }
-
- ///
- /// Restore the target gripper
- ///
- /// StreamingContext
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- InitAdorner(Color.Green, _storedTargetGripperLocation);
- }
-
- public SpeechbubbleContainer(Surface parent)
- : base(parent)
- {
- }
-
- ///
- /// We set our own field values
- ///
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 2);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Blue);
- AddField(GetType(), FieldType.SHADOW, false);
- AddField(GetType(), FieldType.FONT_ITALIC, false);
- AddField(GetType(), FieldType.FONT_BOLD, true);
- AddField(GetType(), FieldType.FILL_COLOR, Color.White);
- AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name);
- AddField(GetType(), FieldType.FONT_SIZE, 20f);
- AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center);
- AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center);
- }
-
- ///
- /// Called from Surface (the _parent) when the drawing begins (mouse-down)
- ///
- /// true if the surface doesn't need to handle the event
- public override bool HandleMouseDown(int mouseX, int mouseY)
- {
- if (TargetAdorner == null)
- {
- _initialGripperPoint = new Point(mouseX, mouseY);
- InitAdorner(Color.Green, new Point(mouseX, mouseY));
- }
-
- return base.HandleMouseDown(mouseX, mouseY);
- }
-
- ///
- /// Overriding the HandleMouseMove will help us to make sure the tail is always visible.
- /// Should fix BUG-1682
- ///
- ///
- ///
- /// base.HandleMouseMove
- public override bool HandleMouseMove(int x, int y)
- {
- bool returnValue = base.HandleMouseMove(x, y);
-
- bool leftAligned = _boundsAfterResize.Right - _boundsAfterResize.Left >= 0;
- bool topAligned = _boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0;
-
- int xOffset = leftAligned ? -20 : 20;
- int yOffset = topAligned ? -20 : 20;
-
- Point newGripperLocation = _initialGripperPoint;
- newGripperLocation.Offset(xOffset, yOffset);
-
- if (TargetAdorner.Location != newGripperLocation)
- {
- Invalidate();
- TargetAdorner.Location = newGripperLocation;
- Invalidate();
- }
-
- return returnValue;
- }
-
- ///
- /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much.
- ///
- public override Rectangle DrawingBounds
- {
- get
- {
- if (Status != EditStatus.UNDRAWN)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- using Pen pen = new Pen(lineColor, lineThickness);
- int inflateValue = lineThickness + 2 + (shadow ? 6 : 0);
- using GraphicsPath tailPath = CreateTail();
- return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)),
- inflateValue, inflateValue);
- }
-
- return Rectangle.Empty;
- }
- }
-
- ///
- /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds
- ///
- ///
- ///
- private GraphicsPath CreateBubble(int lineThickness)
- {
- GraphicsPath bubble = new GraphicsPath();
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
-
- Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height);
- // adapt corner radius to small rectangle dimensions
- int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height);
- int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness);
- if (cornerRadius > 0)
- {
- bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90);
- bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90);
- bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90);
- bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90);
- }
- else
- {
- bubble.AddRectangle(bubbleRect);
- }
-
- bubble.CloseAllFigures();
- using (Matrix bubbleMatrix = new Matrix())
- {
- bubbleMatrix.Translate(rect.Left, rect.Top);
- bubble.Transform(bubbleMatrix);
- }
-
- return bubble;
- }
-
- ///
- /// Helper method to create the tail of the bubble, so we can also calculate the bounds
- ///
- ///
- private GraphicsPath CreateTail()
- {
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
-
- int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y);
- int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20;
-
- // This should fix a problem with the tail being to wide
- tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth);
- tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth);
-
- GraphicsPath tail = new GraphicsPath();
- tail.AddLine(-tailWidth, 0, tailWidth, 0);
- tail.AddLine(tailWidth, 0, 0, -tailLength);
- tail.CloseFigure();
-
- int tailAngle = 90 + (int) GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y);
-
- using (Matrix tailMatrix = new Matrix())
- {
- tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2);
- tailMatrix.Rotate(tailAngle);
- tail.Transform(tailMatrix);
- }
-
- return tail;
- }
-
- ///
- /// This is to draw the actual container
- ///
- ///
- ///
- public override void Draw(Graphics graphics, RenderMode renderMode)
- {
- if (TargetAdorner == null)
- {
- return;
- }
-
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
- graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
-
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
-
- bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
-
- if (Selected && renderMode == RenderMode.EDIT)
- {
- DrawSelectionBorder(graphics, rect);
- }
-
- GraphicsPath bubble = CreateBubble(lineThickness);
-
- GraphicsPath tail = CreateTail();
-
- //draw shadow first
- if (shadow && (lineVisible || Colors.IsVisible(fillColor)))
- {
- const int basealpha = 100;
- int alpha = basealpha;
- const int steps = 5;
- int currentStep = lineVisible ? 1 : 0;
- using Matrix shadowMatrix = new Matrix();
- using GraphicsPath bubbleClone = (GraphicsPath) bubble.Clone();
- using GraphicsPath tailClone = (GraphicsPath) tail.Clone();
- shadowMatrix.Translate(1, 1);
- while (currentStep <= steps)
- {
- using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)))
- {
- shadowPen.Width = lineVisible ? lineThickness : 1;
- tailClone.Transform(shadowMatrix);
- graphics.DrawPath(shadowPen, tailClone);
- bubbleClone.Transform(shadowMatrix);
- graphics.DrawPath(shadowPen, bubbleClone);
- }
-
- currentStep++;
- alpha -= basealpha / steps;
- }
- }
-
- GraphicsState state = graphics.Save();
- // draw the tail border where the bubble is not visible
- using (Region clipRegion = new Region(bubble))
- {
- graphics.SetClip(clipRegion, CombineMode.Exclude);
- using Pen pen = new Pen(lineColor, lineThickness);
- graphics.DrawPath(pen, tail);
- }
-
- graphics.Restore(state);
-
- if (Colors.IsVisible(fillColor))
- {
- //draw the bubbleshape
- state = graphics.Save();
- using (Brush brush = new SolidBrush(fillColor))
- {
- graphics.FillPath(brush, bubble);
- }
-
- graphics.Restore(state);
- }
-
- if (lineVisible)
- {
- //draw the bubble border
- state = graphics.Save();
- // Draw bubble where the Tail is not visible.
- using (Region clipRegion = new Region(tail))
- {
- graphics.SetClip(clipRegion, CombineMode.Exclude);
- using Pen pen = new Pen(lineColor, lineThickness);
- //pen.EndCap = pen.StartCap = LineCap.Round;
- graphics.DrawPath(pen, bubble);
- }
-
- graphics.Restore(state);
- }
-
- if (Colors.IsVisible(fillColor))
- {
- // Draw the tail border
- state = graphics.Save();
- using (Brush brush = new SolidBrush(fillColor))
- {
- graphics.FillPath(brush, tail);
- }
-
- graphics.Restore(state);
- }
-
- // cleanup the paths
- bubble.Dispose();
- tail.Dispose();
-
- // Draw the text
- DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font);
- }
-
- public override bool Contains(int x, int y)
- {
- if (base.Contains(x, y))
- {
- return true;
- }
-
- Point clickedPoint = new Point(x, y);
- if (Status != EditStatus.UNDRAWN)
- {
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- using Pen pen = new Pen(lineColor, lineThickness);
- using (GraphicsPath bubblePath = CreateBubble(lineThickness))
- {
- bubblePath.Widen(pen);
- if (bubblePath.IsVisible(clickedPoint))
- {
- return true;
- }
- }
-
- using GraphicsPath tailPath = CreateTail();
- tailPath.Widen(pen);
- if (tailPath.IsVisible(clickedPoint))
- {
- return true;
- }
- }
-
- return false;
- }
-
- public override bool ClickableAt(int x, int y)
- {
- return Contains(x, y);
- }
-
- ///
- /// Additional to the Transform of the TextContainer the bubble tail coordinates also need to be moved
- ///
- /// Matrix
- public override void Transform(Matrix matrix)
- {
- Point[] points =
- {
- TargetAdorner.Location
- };
- matrix.TransformPoints(points);
- TargetAdorner.Location = points[0];
- base.Transform(matrix);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Text;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of SpeechbubbleContainer.
+ ///
+ [Serializable]
+ public class SpeechbubbleContainer : TextContainer
+ {
+ private Point _initialGripperPoint;
+
+ // Only used for serializing the TargetGripper location
+ private Point _storedTargetGripperLocation;
+
+ ///
+ /// Store the current location of the target gripper
+ ///
+ ///
+ [OnSerializing]
+ private void SetValuesOnSerializing(StreamingContext context)
+ {
+ if (TargetAdorner != null)
+ {
+ _storedTargetGripperLocation = TargetAdorner.Location;
+ }
+ }
+
+ ///
+ /// Restore the target gripper
+ ///
+ /// StreamingContext
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ InitAdorner(Color.Green, _storedTargetGripperLocation);
+ }
+
+ public SpeechbubbleContainer(Surface parent)
+ : base(parent)
+ {
+ }
+
+ ///
+ /// We set our own field values
+ ///
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 2);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Blue);
+ AddField(GetType(), FieldType.SHADOW, false);
+ AddField(GetType(), FieldType.FONT_ITALIC, false);
+ AddField(GetType(), FieldType.FONT_BOLD, true);
+ AddField(GetType(), FieldType.FILL_COLOR, Color.White);
+ AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name);
+ AddField(GetType(), FieldType.FONT_SIZE, 20f);
+ AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center);
+ AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center);
+ }
+
+ ///
+ /// Called from Surface (the _parent) when the drawing begins (mouse-down)
+ ///
+ /// true if the surface doesn't need to handle the event
+ public override bool HandleMouseDown(int mouseX, int mouseY)
+ {
+ if (TargetAdorner == null)
+ {
+ _initialGripperPoint = new Point(mouseX, mouseY);
+ InitAdorner(Color.Green, new Point(mouseX, mouseY));
+ }
+
+ return base.HandleMouseDown(mouseX, mouseY);
+ }
+
+ ///
+ /// Overriding the HandleMouseMove will help us to make sure the tail is always visible.
+ /// Should fix BUG-1682
+ ///
+ ///
+ ///
+ /// base.HandleMouseMove
+ public override bool HandleMouseMove(int x, int y)
+ {
+ bool returnValue = base.HandleMouseMove(x, y);
+
+ bool leftAligned = _boundsAfterResize.Right - _boundsAfterResize.Left >= 0;
+ bool topAligned = _boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0;
+
+ int xOffset = leftAligned ? -20 : 20;
+ int yOffset = topAligned ? -20 : 20;
+
+ Point newGripperLocation = _initialGripperPoint;
+ newGripperLocation.Offset(xOffset, yOffset);
+
+ if (TargetAdorner.Location != newGripperLocation)
+ {
+ Invalidate();
+ TargetAdorner.Location = newGripperLocation;
+ Invalidate();
+ }
+
+ return returnValue;
+ }
+
+ ///
+ /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much.
+ ///
+ public override Rectangle DrawingBounds
+ {
+ get
+ {
+ if (Status != EditStatus.UNDRAWN)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ using Pen pen = new Pen(lineColor, lineThickness);
+ int inflateValue = lineThickness + 2 + (shadow ? 6 : 0);
+ using GraphicsPath tailPath = CreateTail();
+ return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)),
+ inflateValue, inflateValue);
+ }
+
+ return Rectangle.Empty;
+ }
+ }
+
+ ///
+ /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds
+ ///
+ ///
+ ///
+ private GraphicsPath CreateBubble(int lineThickness)
+ {
+ GraphicsPath bubble = new GraphicsPath();
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+
+ Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height);
+ // adapt corner radius to small rectangle dimensions
+ int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height);
+ int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness);
+ if (cornerRadius > 0)
+ {
+ bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90);
+ bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90);
+ bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90);
+ bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90);
+ }
+ else
+ {
+ bubble.AddRectangle(bubbleRect);
+ }
+
+ bubble.CloseAllFigures();
+ using (Matrix bubbleMatrix = new Matrix())
+ {
+ bubbleMatrix.Translate(rect.Left, rect.Top);
+ bubble.Transform(bubbleMatrix);
+ }
+
+ return bubble;
+ }
+
+ ///
+ /// Helper method to create the tail of the bubble, so we can also calculate the bounds
+ ///
+ ///
+ private GraphicsPath CreateTail()
+ {
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+
+ int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y);
+ int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20;
+
+ // This should fix a problem with the tail being to wide
+ tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth);
+ tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth);
+
+ GraphicsPath tail = new GraphicsPath();
+ tail.AddLine(-tailWidth, 0, tailWidth, 0);
+ tail.AddLine(tailWidth, 0, 0, -tailLength);
+ tail.CloseFigure();
+
+ int tailAngle = 90 + (int) GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y);
+
+ using (Matrix tailMatrix = new Matrix())
+ {
+ tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2);
+ tailMatrix.Rotate(tailAngle);
+ tail.Transform(tailMatrix);
+ }
+
+ return tail;
+ }
+
+ ///
+ /// This is to draw the actual container
+ ///
+ ///
+ ///
+ public override void Draw(Graphics graphics, RenderMode renderMode)
+ {
+ if (TargetAdorner == null)
+ {
+ return;
+ }
+
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+ graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
+
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+
+ bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+
+ if (Selected && renderMode == RenderMode.EDIT)
+ {
+ DrawSelectionBorder(graphics, rect);
+ }
+
+ GraphicsPath bubble = CreateBubble(lineThickness);
+
+ GraphicsPath tail = CreateTail();
+
+ //draw shadow first
+ if (shadow && (lineVisible || Colors.IsVisible(fillColor)))
+ {
+ const int basealpha = 100;
+ int alpha = basealpha;
+ const int steps = 5;
+ int currentStep = lineVisible ? 1 : 0;
+ using Matrix shadowMatrix = new Matrix();
+ using GraphicsPath bubbleClone = (GraphicsPath) bubble.Clone();
+ using GraphicsPath tailClone = (GraphicsPath) tail.Clone();
+ shadowMatrix.Translate(1, 1);
+ while (currentStep <= steps)
+ {
+ using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)))
+ {
+ shadowPen.Width = lineVisible ? lineThickness : 1;
+ tailClone.Transform(shadowMatrix);
+ graphics.DrawPath(shadowPen, tailClone);
+ bubbleClone.Transform(shadowMatrix);
+ graphics.DrawPath(shadowPen, bubbleClone);
+ }
+
+ currentStep++;
+ alpha -= basealpha / steps;
+ }
+ }
+
+ GraphicsState state = graphics.Save();
+ // draw the tail border where the bubble is not visible
+ using (Region clipRegion = new Region(bubble))
+ {
+ graphics.SetClip(clipRegion, CombineMode.Exclude);
+ using Pen pen = new Pen(lineColor, lineThickness);
+ graphics.DrawPath(pen, tail);
+ }
+
+ graphics.Restore(state);
+
+ if (Colors.IsVisible(fillColor))
+ {
+ //draw the bubbleshape
+ state = graphics.Save();
+ using (Brush brush = new SolidBrush(fillColor))
+ {
+ graphics.FillPath(brush, bubble);
+ }
+
+ graphics.Restore(state);
+ }
+
+ if (lineVisible)
+ {
+ //draw the bubble border
+ state = graphics.Save();
+ // Draw bubble where the Tail is not visible.
+ using (Region clipRegion = new Region(tail))
+ {
+ graphics.SetClip(clipRegion, CombineMode.Exclude);
+ using Pen pen = new Pen(lineColor, lineThickness);
+ //pen.EndCap = pen.StartCap = LineCap.Round;
+ graphics.DrawPath(pen, bubble);
+ }
+
+ graphics.Restore(state);
+ }
+
+ if (Colors.IsVisible(fillColor))
+ {
+ // Draw the tail border
+ state = graphics.Save();
+ using (Brush brush = new SolidBrush(fillColor))
+ {
+ graphics.FillPath(brush, tail);
+ }
+
+ graphics.Restore(state);
+ }
+
+ // cleanup the paths
+ bubble.Dispose();
+ tail.Dispose();
+
+ // Draw the text
+ DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font);
+ }
+
+ public override bool Contains(int x, int y)
+ {
+ if (base.Contains(x, y))
+ {
+ return true;
+ }
+
+ Point clickedPoint = new Point(x, y);
+ if (Status != EditStatus.UNDRAWN)
+ {
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ using Pen pen = new Pen(lineColor, lineThickness);
+ using (GraphicsPath bubblePath = CreateBubble(lineThickness))
+ {
+ bubblePath.Widen(pen);
+ if (bubblePath.IsVisible(clickedPoint))
+ {
+ return true;
+ }
+ }
+
+ using GraphicsPath tailPath = CreateTail();
+ tailPath.Widen(pen);
+ if (tailPath.IsVisible(clickedPoint))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ return Contains(x, y);
+ }
+
+ ///
+ /// Additional to the Transform of the TextContainer the bubble tail coordinates also need to be moved
+ ///
+ /// Matrix
+ public override void Transform(Matrix matrix)
+ {
+ Point[] points =
+ {
+ TargetAdorner.Location
+ };
+ matrix.TransformPoints(points);
+ TargetAdorner.Location = points[0];
+ base.Transform(matrix);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/StepLabelContainer.cs b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/StepLabelContainer.cs
rename to src/Greenshot.Editor/Drawing/StepLabelContainer.cs
index 41f78da09..0e7c27516 100644
--- a/src/Greenshot/Drawing/StepLabelContainer.cs
+++ b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs
@@ -1,225 +1,225 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Text;
-using System.Runtime.Serialization;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created.
- /// To make sure that deleting recalculates, we check the location before every draw.
- ///
- [Serializable]
- public sealed class StepLabelContainer : DrawableContainer
- {
- [NonSerialized] private StringFormat _stringFormat = new StringFormat();
-
- private readonly bool _drawAsRectangle = false;
-
- public StepLabelContainer(Surface parent) : base(parent)
- {
- parent.AddStepLabel(this);
- InitContent();
- Init();
- }
-
- private void Init()
- {
- CreateDefaultAdorners();
- }
-
- // Used to store the number of this label, so when deserializing it can be placed back to the StepLabels list in the right location
- private int _number;
-
- // Used to store the counter start of the Surface, as the surface is NOT stored.
- private int _counterStart = 1;
-
- public int Number
- {
- get { return _number; }
- set { _number = value; }
- }
-
- ///
- /// Retrieve the counter before serializing
- ///
- ///
- [OnSerializing]
- private void SetValuesOnSerializing(StreamingContext context)
- {
- if (Parent != null)
- {
- Number = ((Surface) Parent).CountStepLabels(this);
- _counterStart = ((Surface) Parent).CounterStart;
- }
- }
-
- ///
- /// Restore values that don't serialize
- ///
- ///
- protected override void OnDeserialized(StreamingContext context)
- {
- Init();
- _stringFormat = new StringFormat
- {
- Alignment = StringAlignment.Center,
- LineAlignment = StringAlignment.Center
- };
- }
-
- ///
- /// Add the StepLabel to the parent
- ///
- ///
- protected override void SwitchParent(Surface newParent)
- {
- if (newParent == Parent)
- {
- return;
- }
-
- ((Surface) Parent)?.RemoveStepLabel(this);
- base.SwitchParent(newParent);
- if (newParent == null)
- {
- return;
- }
-
- // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack)
- newParent.CounterStart = _counterStart;
- newParent.AddStepLabel(this);
- }
-
- public override Size DefaultSize => new Size(30, 30);
-
- public override bool InitContent()
- {
- _defaultEditMode = EditStatus.IDLE;
- _stringFormat.Alignment = StringAlignment.Center;
- _stringFormat.LineAlignment = StringAlignment.Center;
-
- // Set defaults
- Width = DefaultSize.Width;
- Height = DefaultSize.Height;
-
- return true;
- }
-
- ///
- /// This makes it possible for the label to be placed exactly in the middle of the pointer.
- ///
- public override bool HandleMouseDown(int mouseX, int mouseY)
- {
- return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2);
- }
-
- ///
- /// We set our own field values
- ///
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed);
- AddField(GetType(), FieldType.LINE_COLOR, Color.White);
- AddField(GetType(), FieldType.FLAGS, FieldFlag.COUNTER);
- }
-
- ///
- /// Make sure this element is no longer referenced from the surface
- ///
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- if (!disposing)
- {
- return;
- }
-
- ((Surface) Parent)?.RemoveStepLabel(this);
- if (_stringFormat == null)
- {
- return;
- }
-
- _stringFormat.Dispose();
- _stringFormat = null;
- }
-
- public override bool HandleMouseMove(int x, int y)
- {
- Invalidate();
- Left = x - Width / 2;
- Top = y - Height / 2;
- Invalidate();
- return true;
- }
-
- ///
- /// Override the parent, calculate the label number, than draw
- ///
- ///
- ///
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
- graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
- string text = ((Surface) Parent).CountStepLabels(this).ToString();
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- if (_drawAsRectangle)
- {
- RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
- }
- else
- {
- EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
- }
-
- float fontSize = Math.Min(Width, Height) / 1.4f;
- using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name);
- using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
- TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font);
- }
-
- public override bool ClickableAt(int x, int y)
- {
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
- if (_drawAsRectangle)
- {
- return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y);
- }
-
- return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Text;
+using System.Runtime.Serialization;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created.
+ /// To make sure that deleting recalculates, we check the location before every draw.
+ ///
+ [Serializable]
+ public sealed class StepLabelContainer : DrawableContainer
+ {
+ [NonSerialized] private StringFormat _stringFormat = new StringFormat();
+
+ private readonly bool _drawAsRectangle = false;
+
+ public StepLabelContainer(Surface parent) : base(parent)
+ {
+ parent.AddStepLabel(this);
+ InitContent();
+ Init();
+ }
+
+ private void Init()
+ {
+ CreateDefaultAdorners();
+ }
+
+ // Used to store the number of this label, so when deserializing it can be placed back to the StepLabels list in the right location
+ private int _number;
+
+ // Used to store the counter start of the Surface, as the surface is NOT stored.
+ private int _counterStart = 1;
+
+ public int Number
+ {
+ get { return _number; }
+ set { _number = value; }
+ }
+
+ ///
+ /// Retrieve the counter before serializing
+ ///
+ ///
+ [OnSerializing]
+ private void SetValuesOnSerializing(StreamingContext context)
+ {
+ if (Parent != null)
+ {
+ Number = ((Surface) Parent).CountStepLabels(this);
+ _counterStart = ((Surface) Parent).CounterStart;
+ }
+ }
+
+ ///
+ /// Restore values that don't serialize
+ ///
+ ///
+ protected override void OnDeserialized(StreamingContext context)
+ {
+ Init();
+ _stringFormat = new StringFormat
+ {
+ Alignment = StringAlignment.Center,
+ LineAlignment = StringAlignment.Center
+ };
+ }
+
+ ///
+ /// Add the StepLabel to the parent
+ ///
+ ///
+ protected override void SwitchParent(Surface newParent)
+ {
+ if (newParent == Parent)
+ {
+ return;
+ }
+
+ ((Surface) Parent)?.RemoveStepLabel(this);
+ base.SwitchParent(newParent);
+ if (newParent == null)
+ {
+ return;
+ }
+
+ // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack)
+ newParent.CounterStart = _counterStart;
+ newParent.AddStepLabel(this);
+ }
+
+ public override Size DefaultSize => new Size(30, 30);
+
+ public override bool InitContent()
+ {
+ _defaultEditMode = EditStatus.IDLE;
+ _stringFormat.Alignment = StringAlignment.Center;
+ _stringFormat.LineAlignment = StringAlignment.Center;
+
+ // Set defaults
+ Width = DefaultSize.Width;
+ Height = DefaultSize.Height;
+
+ return true;
+ }
+
+ ///
+ /// This makes it possible for the label to be placed exactly in the middle of the pointer.
+ ///
+ public override bool HandleMouseDown(int mouseX, int mouseY)
+ {
+ return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2);
+ }
+
+ ///
+ /// We set our own field values
+ ///
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.White);
+ AddField(GetType(), FieldType.FLAGS, FieldFlag.COUNTER);
+ }
+
+ ///
+ /// Make sure this element is no longer referenced from the surface
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing)
+ {
+ return;
+ }
+
+ ((Surface) Parent)?.RemoveStepLabel(this);
+ if (_stringFormat == null)
+ {
+ return;
+ }
+
+ _stringFormat.Dispose();
+ _stringFormat = null;
+ }
+
+ public override bool HandleMouseMove(int x, int y)
+ {
+ Invalidate();
+ Left = x - Width / 2;
+ Top = y - Height / 2;
+ Invalidate();
+ return true;
+ }
+
+ ///
+ /// Override the parent, calculate the label number, than draw
+ ///
+ ///
+ ///
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+ graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
+ string text = ((Surface) Parent).CountStepLabels(this).ToString();
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ if (_drawAsRectangle)
+ {
+ RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
+ }
+ else
+ {
+ EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
+ }
+
+ float fontSize = Math.Min(Width, Height) / 1.4f;
+ using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name);
+ using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
+ TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font);
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+ if (_drawAsRectangle)
+ {
+ return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y);
+ }
+
+ return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs
similarity index 97%
rename from src/Greenshot/Drawing/Surface.cs
rename to src/Greenshot.Editor/Drawing/Surface.cs
index 3fafc49fe..7fd7485d0 100644
--- a/src/Greenshot/Drawing/Surface.cs
+++ b/src/Greenshot.Editor/Drawing/Surface.cs
@@ -1,2367 +1,2367 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Configuration;
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using Greenshot.Memento;
-using log4net;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Runtime.Serialization.Formatters.Binary;
-using System.Windows.Forms;
-using Greenshot.Base.Controls;
-using Greenshot.Base.Core;
-using Greenshot.Base.Effects;
-using Greenshot.Base.IniFile;
-using Greenshot.Base.Interfaces;
-using Greenshot.Base.Interfaces.Drawing;
-using Greenshot.Base.Interfaces.Drawing.Adorners;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Description of Surface.
- ///
- public sealed class Surface : Control, ISurface, INotifyPropertyChanged
- {
- private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface));
- public static int Count;
- private static readonly CoreConfiguration conf = IniConfig.GetIniSection();
-
- // Property to identify the Surface ID
- private Guid _uniqueId = Guid.NewGuid();
-
- ///
- /// This value is used to start counting the step labels
- ///
- private int _counterStart = 1;
-
- ///
- /// The GUID of the surface
- ///
- public Guid ID
- {
- get => _uniqueId;
- set => _uniqueId = value;
- }
-
- ///
- /// Event handlers (do not serialize!)
- ///
- [NonSerialized] private PropertyChangedEventHandler _propertyChanged;
-
- public event PropertyChangedEventHandler PropertyChanged
- {
- add => _propertyChanged += value;
- remove => _propertyChanged -= value;
- }
-
- [NonSerialized] private SurfaceElementEventHandler _movingElementChanged;
-
- public event SurfaceElementEventHandler MovingElementChanged
- {
- add => _movingElementChanged += value;
- remove => _movingElementChanged -= value;
- }
-
- [NonSerialized] private SurfaceDrawingModeEventHandler _drawingModeChanged;
-
- public event SurfaceDrawingModeEventHandler DrawingModeChanged
- {
- add => _drawingModeChanged += value;
- remove => _drawingModeChanged -= value;
- }
-
- [NonSerialized] private SurfaceSizeChangeEventHandler _surfaceSizeChanged;
-
- public event SurfaceSizeChangeEventHandler SurfaceSizeChanged
- {
- add => _surfaceSizeChanged += value;
- remove => _surfaceSizeChanged -= value;
- }
-
- [NonSerialized] private SurfaceMessageEventHandler _surfaceMessage;
-
- public event SurfaceMessageEventHandler SurfaceMessage
- {
- add => _surfaceMessage += value;
- remove => _surfaceMessage -= value;
- }
-
- ///
- /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action
- ///
- [NonSerialized] private bool _inUndoRedo;
-
- ///
- /// Make only one surface move cycle undoable, see SurfaceMouseMove
- ///
- [NonSerialized] private bool _isSurfaceMoveMadeUndoable;
-
- ///
- /// Undo/Redo stacks, should not be serialized as the file would be way to big
- ///
- [NonSerialized] private readonly Stack _undoStack = new Stack();
-
- [NonSerialized] private readonly Stack _redoStack = new Stack();
-
- ///
- /// Last save location, do not serialize!
- ///
- [NonSerialized] private string _lastSaveFullPath;
-
- ///
- /// current drawing mode, do not serialize!
- ///
- [NonSerialized] private DrawingModes _drawingMode = DrawingModes.None;
-
- ///
- /// the keys-locked flag helps with focus issues
- ///
- [NonSerialized] private bool _keysLocked;
-
- ///
- /// Location of the mouse-down (it "starts" here), do not serialize
- ///
- [NonSerialized] private Point _mouseStart = Point.Empty;
-
- ///
- /// are we in a mouse down, do not serialize
- ///
- [NonSerialized] private bool _mouseDown;
-
- ///
- /// The selected element for the mouse down, do not serialize
- ///
- [NonSerialized] private IDrawableContainer _mouseDownElement;
-
- ///
- /// all selected elements, do not serialize
- ///
- [NonSerialized] private readonly IDrawableContainerList selectedElements;
-
- ///
- /// the element we are drawing with, do not serialize
- ///
- [NonSerialized] private IDrawableContainer _drawingElement;
-
- ///
- /// the element we want to draw with (not yet drawn), do not serialize
- ///
- [NonSerialized] private IDrawableContainer _undrawnElement;
-
- ///
- /// the cropcontainer, when cropping this is set, do not serialize
- ///
- [NonSerialized] private IDrawableContainer _cropContainer;
-
- ///
- /// the brush which is used for transparent backgrounds, set by the editor, do not serialize
- ///
- [NonSerialized] private Brush _transparencyBackgroundBrush;
-
- ///
- /// The buffer is only for drawing on it when using filters (to supply access)
- /// This saves a lot of "create new bitmap" commands
- /// Should not be serialized, as it's generated.
- /// The actual bitmap is in the paintbox...
- /// TODO: Check if this buffer is still needed!
- ///
- [NonSerialized] private Bitmap _buffer;
-
- ///
- /// all stepLabels for the surface, needed with serialization
- ///
- private readonly List _stepLabels = new List();
-
- public void AddStepLabel(StepLabelContainer stepLabel)
- {
- if (!_stepLabels.Contains(stepLabel))
- {
- _stepLabels.Add(stepLabel);
- }
- }
-
- public void RemoveStepLabel(StepLabelContainer stepLabel)
- {
- _stepLabels.Remove(stepLabel);
- }
-
- ///
- /// The start value of the counter objects
- ///
- public int CounterStart
- {
- get => _counterStart;
- set
- {
- if (_counterStart == value)
- {
- return;
- }
-
- _counterStart = value;
- Invalidate();
- _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CounterStart)));
- }
- }
-
- ///
- /// Count all the VISIBLE steplabels in the surface, up to the supplied one
- ///
- /// can be null, if not the counting stops here
- /// number of steplabels before the supplied container
- public int CountStepLabels(IDrawableContainer stopAtContainer)
- {
- int number = CounterStart;
- foreach (var possibleThis in _stepLabels)
- {
- if (possibleThis.Equals(stopAtContainer))
- {
- break;
- }
-
- if (IsOnSurface(possibleThis))
- {
- number++;
- }
- }
-
- return number;
- }
-
- ///
- /// all elements on the surface, needed with serialization
- ///
- private readonly IDrawableContainerList _elements;
-
- ///
- /// all elements on the surface, needed with serialization
- ///
- private FieldAggregator _fieldAggregator;
-
- ///
- /// the cursor container, needed with serialization as we need a direct acces to it.
- ///
- private IDrawableContainer _cursorContainer;
-
- ///
- /// the modified flag specifies if the surface has had modifications after the last export.
- /// Initial state is modified, as "it's not saved"
- /// After serialization this should actually be "false" (the surface came from a stream)
- /// For now we just serialize it...
- ///
- private bool _modified = true;
-
- ///
- /// The image is the actual captured image, needed with serialization
- ///
- private Image _image;
-
- public Image Image
- {
- get => _image;
- set
- {
- _image = value;
- 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();
- }
- }
-
-
- ///
- /// Sets the surface size as zoomed image size.
- ///
- private void UpdateSize()
- {
- var size = _image.Size;
- Size = new Size((int) (size.Width * _zoomFactor), (int) (size.Height * _zoomFactor));
- }
-
- ///
- /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements.
- /// e.g. used to decided if and which line thickness is shown when multiple elements are selected.
- ///
- public FieldAggregator FieldAggregator
- {
- get => _fieldAggregator;
- set => _fieldAggregator = value;
- }
-
- ///
- /// The cursor container has it's own accessor so we can find and remove this (when needed)
- ///
- public IDrawableContainer CursorContainer => _cursorContainer;
-
- ///
- /// A simple getter to ask if this surface has a cursor
- ///
- public bool HasCursor => _cursorContainer != null;
-
- ///
- /// A simple helper method to remove the cursor from the surface
- ///
- public void RemoveCursor()
- {
- RemoveElement(_cursorContainer);
- _cursorContainer = null;
- }
-
- ///
- /// The brush which is used to draw the transparent background
- ///
- public Brush TransparencyBackgroundBrush
- {
- get => _transparencyBackgroundBrush;
- set => _transparencyBackgroundBrush = value;
- }
-
- ///
- /// Are the keys on this surface locked?
- ///
- public bool KeysLocked
- {
- get => _keysLocked;
- set => _keysLocked = value;
- }
-
- ///
- /// Is this surface modified? This is only true if the surface has not been exported.
- ///
- public bool Modified
- {
- get => _modified;
- set => _modified = value;
- }
-
- ///
- /// The DrawingMode property specifies the mode for drawing, more or less the element type.
- ///
- public DrawingModes DrawingMode
- {
- get => _drawingMode;
- set
- {
- _drawingMode = value;
- if (_drawingModeChanged != null)
- {
- SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs
- {
- DrawingMode = _drawingMode
- };
- _drawingModeChanged.Invoke(this, eventArgs);
- }
-
- DeselectAllElements();
- CreateUndrawnElement();
- }
- }
-
- ///
- /// Property for accessing the last save "full" path
- ///
- public string LastSaveFullPath
- {
- get => _lastSaveFullPath;
- set => _lastSaveFullPath = value;
- }
-
- ///
- /// Property for accessing the URL to which the surface was recently uploaded
- ///
- public string UploadUrl { get; set; }
-
- ///
- /// Property for accessing the capture details
- ///
- public ICaptureDetails CaptureDetails { get; set; }
-
- ///
- /// Adjust UI elements to the supplied DPI settings
- ///
- ///
- public void AdjustToDpi(uint dpi)
- {
- foreach (var element in this._elements)
- {
- element.AdjustToDpi(dpi);
- }
- }
-
- ///
- /// Base Surface constructor
- ///
- public Surface()
- {
- _fieldAggregator = new FieldAggregator(this);
- Count++;
- _elements = new DrawableContainerList(_uniqueId);
- selectedElements = new DrawableContainerList(_uniqueId);
- LOG.Debug("Creating surface!");
- MouseDown += SurfaceMouseDown;
- MouseUp += SurfaceMouseUp;
- MouseMove += SurfaceMouseMove;
- MouseDoubleClick += SurfaceDoubleClick;
- Paint += SurfacePaint;
- AllowDrop = true;
- DragDrop += OnDragDrop;
- DragEnter += OnDragEnter;
- // bind selected & elements to this, otherwise they can't inform of modifications
- selectedElements.Parent = this;
- _elements.Parent = this;
- // Make sure we are visible
- Visible = true;
- TabStop = false;
- // Enable double buffering
- DoubleBuffered = true;
- SetStyle(
- ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer |
- ControlStyles.SupportsTransparentBackColor, true);
- }
-
- ///
- /// Private method, the current image is disposed the new one will stay.
- ///
- /// The new image
- /// true if the old image needs to be disposed, when using undo this should not be true!!
- private void SetImage(Image newImage, bool dispose)
- {
- // Dispose
- if (_image != null && dispose)
- {
- _image.Dispose();
- }
-
- // Set new values
- Image = newImage;
-
- _modified = true;
- }
-
- ///
- /// Surface constructor with an image
- ///
- ///
- public Surface(Image newImage) : this()
- {
- LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat);
- SetImage(newImage, true);
- }
-
- ///
- /// Surface contructor with a capture
- ///
- ///
- public Surface(ICapture capture) : this(capture.Image)
- {
- // check if cursor is captured, and visible
- if (capture.Cursor != null && capture.CursorVisible)
- {
- Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size);
- Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size);
- // check if cursor is on the capture, otherwise we leave it out.
- if (cursorRect.IntersectsWith(captureRect))
- {
- _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y);
- SelectElement(_cursorContainer);
- }
- }
-
- // Make sure the image is NOT disposed, we took the reference directly into ourselves
- ((Capture) capture).NullImage();
-
- CaptureDetails = capture.CaptureDetails;
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- Count--;
- LOG.Debug("Disposing surface!");
- if (_buffer != null)
- {
- _buffer.Dispose();
- _buffer = null;
- }
-
- if (_transparencyBackgroundBrush != null)
- {
- _transparencyBackgroundBrush.Dispose();
- _transparencyBackgroundBrush = null;
- }
-
- // Cleanup undo/redo stacks
- while (_undoStack != null && _undoStack.Count > 0)
- {
- _undoStack.Pop().Dispose();
- }
-
- while (_redoStack != null && _redoStack.Count > 0)
- {
- _redoStack.Pop().Dispose();
- }
-
- foreach (IDrawableContainer container in _elements)
- {
- container.Dispose();
- }
-
- if (_undrawnElement != null)
- {
- _undrawnElement.Dispose();
- _undrawnElement = null;
- }
-
- if (_cropContainer != null)
- {
- _cropContainer.Dispose();
- _cropContainer = null;
- }
- }
-
- base.Dispose(disposing);
- }
-
- ///
- /// Undo the last action
- ///
- public void Undo()
- {
- if (_undoStack.Count > 0)
- {
- _inUndoRedo = true;
- IMemento top = _undoStack.Pop();
- _redoStack.Push(top.Restore());
- _inUndoRedo = false;
- }
- }
-
- ///
- /// Undo an undo (=redo)
- ///
- public void Redo()
- {
- if (_redoStack.Count > 0)
- {
- _inUndoRedo = true;
- IMemento top = _redoStack.Pop();
- _undoStack.Push(top.Restore());
- _inUndoRedo = false;
- }
- }
-
- ///
- /// Returns if the surface can do a undo
- ///
- public bool CanUndo => _undoStack.Count > 0;
-
- ///
- /// Returns if the surface can do a redo
- ///
- public bool CanRedo => _redoStack.Count > 0;
-
- ///
- /// Get the language key for the undo action
- ///
- public LangKey UndoActionLanguageKey => LangKey.none;
-
- ///
- /// Get the language key for redo action
- ///
- public LangKey RedoActionLanguageKey => LangKey.none;
-
- ///
- /// Make an action undo-able
- ///
- /// The memento implementing the undo
- /// Allow changes to be merged
- public void MakeUndoable(IMemento memento, bool allowMerge)
- {
- if (_inUndoRedo)
- {
- throw new InvalidOperationException("Invoking do within an undo/redo action.");
- }
-
- if (memento != null)
- {
- bool allowPush = true;
- if (_undoStack.Count > 0 && allowMerge)
- {
- // Check if merge is possible
- allowPush = !_undoStack.Peek().Merge(memento);
- }
-
- if (allowPush)
- {
- // Clear the redo-stack and dispose
- while (_redoStack.Count > 0)
- {
- _redoStack.Pop().Dispose();
- }
-
- _undoStack.Push(memento);
- }
- }
- }
-
- ///
- /// This saves the elements of this surface to a stream.
- /// Is used to save a template of the complete surface
- ///
- ///
- ///
- public long SaveElementsToStream(Stream streamWrite)
- {
- long bytesWritten = 0;
- try
- {
- long lengtBefore = streamWrite.Length;
- BinaryFormatter binaryWrite = new BinaryFormatter();
- binaryWrite.Serialize(streamWrite, _elements);
- bytesWritten = streamWrite.Length - lengtBefore;
- }
- catch (Exception e)
- {
- LOG.Error("Error serializing elements to stream.", e);
- }
-
- return bytesWritten;
- }
-
- ///
- /// This loads elements from a stream, among others this is used to load a surface.
- ///
- ///
- public void LoadElementsFromStream(Stream streamRead)
- {
- try
- {
- BinaryFormatter binaryRead = new BinaryFormatter();
- IDrawableContainerList loadedElements = (IDrawableContainerList) binaryRead.Deserialize(streamRead);
- loadedElements.Parent = this;
- // Make sure the steplabels are sorted accoring to their number
- _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number));
- DeselectAllElements();
- AddElements(loadedElements);
- SelectElements(loadedElements);
- FieldAggregator.BindElements(loadedElements);
- }
- catch (Exception e)
- {
- LOG.Error("Error serializing elements from stream.", e);
- }
- }
-
- ///
- /// This is called from the DrawingMode setter, which is not very correct...
- /// But here an element is created which is not yet draw, thus "undrawnElement".
- /// The element is than used while drawing on the surface.
- ///
- private void CreateUndrawnElement()
- {
- if (_undrawnElement != null)
- {
- FieldAggregator.UnbindElement(_undrawnElement);
- }
-
- switch (DrawingMode)
- {
- case DrawingModes.Rect:
- _undrawnElement = new RectangleContainer(this);
- break;
- case DrawingModes.Ellipse:
- _undrawnElement = new EllipseContainer(this);
- break;
- case DrawingModes.Text:
- _undrawnElement = new TextContainer(this);
- break;
- case DrawingModes.SpeechBubble:
- _undrawnElement = new SpeechbubbleContainer(this);
- break;
- case DrawingModes.StepLabel:
- _undrawnElement = new StepLabelContainer(this);
- break;
- case DrawingModes.Line:
- _undrawnElement = new LineContainer(this);
- break;
- case DrawingModes.Arrow:
- _undrawnElement = new ArrowContainer(this);
- break;
- case DrawingModes.Highlight:
- _undrawnElement = new HighlightContainer(this);
- break;
- case DrawingModes.Obfuscate:
- _undrawnElement = new ObfuscateContainer(this);
- break;
- case DrawingModes.Crop:
- _cropContainer = new CropContainer(this);
- _undrawnElement = _cropContainer;
- break;
- case DrawingModes.Bitmap:
- _undrawnElement = new ImageContainer(this);
- break;
- case DrawingModes.Path:
- _undrawnElement = new FreehandContainer(this);
- break;
- case DrawingModes.None:
- _undrawnElement = null;
- break;
- }
-
- if (_undrawnElement != null)
- {
- FieldAggregator.BindElement(_undrawnElement);
- }
- }
-
- #region Plugin interface implementations
-
- public IImageContainer AddImageContainer(Image image, int x, int y)
- {
- ImageContainer bitmapContainer = new ImageContainer(this)
- {
- Image = image,
- Left = x,
- Top = y
- };
- AddElement(bitmapContainer);
- return bitmapContainer;
- }
-
- public IImageContainer AddImageContainer(string filename, int x, int y)
- {
- ImageContainer bitmapContainer = new ImageContainer(this);
- bitmapContainer.Load(filename);
- bitmapContainer.Left = x;
- bitmapContainer.Top = y;
- AddElement(bitmapContainer);
- return bitmapContainer;
- }
-
- public IIconContainer AddIconContainer(Icon icon, int x, int y)
- {
- IconContainer iconContainer = new IconContainer(this)
- {
- Icon = icon,
- Left = x,
- Top = y
- };
- AddElement(iconContainer);
- return iconContainer;
- }
-
- public IIconContainer AddIconContainer(string filename, int x, int y)
- {
- IconContainer iconContainer = new IconContainer(this);
- iconContainer.Load(filename);
- iconContainer.Left = x;
- iconContainer.Top = y;
- AddElement(iconContainer);
- return iconContainer;
- }
-
- public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y)
- {
- CursorContainer cursorContainer = new CursorContainer(this)
- {
- Cursor = cursor,
- Left = x,
- Top = y
- };
- AddElement(cursorContainer);
- return cursorContainer;
- }
-
- public ICursorContainer AddCursorContainer(string filename, int x, int y)
- {
- CursorContainer cursorContainer = new CursorContainer(this);
- cursorContainer.Load(filename);
- cursorContainer.Left = x;
- cursorContainer.Top = y;
- AddElement(cursorContainer);
- return cursorContainer;
- }
-
- 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,
- Left = x,
- Top = y
- };
- textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name);
- textContainer.SetFieldValue(FieldType.FONT_BOLD, bold);
- textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic);
- textContainer.SetFieldValue(FieldType.FONT_SIZE, size);
- textContainer.SetFieldValue(FieldType.FILL_COLOR, fillColor);
- textContainer.SetFieldValue(FieldType.LINE_COLOR, color);
- textContainer.SetFieldValue(FieldType.LINE_THICKNESS, borderSize);
- textContainer.SetFieldValue(FieldType.SHADOW, shadow);
- // Make sure the Text fits
- textContainer.FitToText();
-
- //AggregatedProperties.UpdateElement(textContainer);
- AddElement(textContainer);
- return textContainer;
- }
-
- #endregion
-
- #region DragDrop
-
- private void OnDragEnter(object sender, DragEventArgs e)
- {
- if (LOG.IsDebugEnabled)
- {
- LOG.Debug("DragEnter got following formats: ");
- foreach (string format in ClipboardHelper.GetFormats(e.Data))
- {
- LOG.Debug(format);
- }
- }
-
- if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy)
- {
- e.Effect = DragDropEffects.None;
- }
- else
- {
- if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits"))
- {
- e.Effect = DragDropEffects.Copy;
- }
- else
- {
- e.Effect = DragDropEffects.None;
- }
- }
- }
-
- ///
- /// Handle the drag/drop
- ///
- ///
- ///
- private void OnDragDrop(object sender, DragEventArgs e)
- {
- Point mouse = PointToClient(new Point(e.X, e.Y));
- if (e.Data.GetDataPresent("Text"))
- {
- string possibleUrl = ClipboardHelper.GetText(e.Data);
- // Test if it's an url and try to download the image so we have it in the original form
- if (possibleUrl != null && possibleUrl.StartsWith("http"))
- {
- using Image image = NetworkHelper.DownloadImage(possibleUrl);
- if (image != null)
- {
- AddImageContainer(image, mouse.X, mouse.Y);
- return;
- }
- }
- }
-
- foreach (Image image in ClipboardHelper.GetImages(e.Data))
- {
- AddImageContainer(image, mouse.X, mouse.Y);
- mouse.Offset(10, 10);
- image.Dispose();
- }
- }
-
- #endregion
-
- ///
- /// Auto crop the image
- ///
- /// true if cropped
- public bool AutoCrop()
- {
- Rectangle cropRectangle;
- using (Image tmpImage = GetImageForExport())
- {
- cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference);
- }
-
- if (!IsCropPossible(ref cropRectangle))
- {
- return false;
- }
-
- DeselectAllElements();
- // Maybe a bit obscure, but the following line creates a drop container
- // It's available as "undrawnElement"
- DrawingMode = DrawingModes.Crop;
- _undrawnElement.Left = cropRectangle.X;
- _undrawnElement.Top = cropRectangle.Y;
- _undrawnElement.Width = cropRectangle.Width;
- _undrawnElement.Height = cropRectangle.Height;
- _undrawnElement.Status = EditStatus.UNDRAWN;
- AddElement(_undrawnElement);
- SelectElement(_undrawnElement);
- _drawingElement = null;
- _undrawnElement = null;
- return true;
- }
-
- ///
- /// A simple clear
- ///
- /// The color for the background
- public void Clear(Color newColor)
- {
- //create a blank bitmap the same size as original
- Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty);
- if (newBitmap != null)
- {
- // Make undoable
- MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false);
- SetImage(newBitmap, false);
- Invalidate();
- }
- }
-
- ///
- /// Apply a bitmap effect to the surface
- ///
- ///
- public void ApplyBitmapEffect(IEffect effect)
- {
- BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait");
- backgroundForm.Show();
- Application.DoEvents();
- try
- {
- Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
- Matrix matrix = new Matrix();
- Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix);
- if (newImage != null)
- {
- // Make sure the elements move according to the offset the effect made the bitmap move
- _elements.Transform(matrix);
- // Make undoable
- MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false);
- SetImage(newImage, false);
- Invalidate();
- if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size)))
- {
- _surfaceSizeChanged(this, null);
- }
- }
- else
- {
- // clean up matrix, as it hasn't been used in the undo stack.
- matrix.Dispose();
- }
- }
- finally
- {
- // Always close the background form
- backgroundForm.CloseDialog();
- }
- }
-
- ///
- /// check if a crop is possible
- ///
- ///
- /// true if this is possible
- public bool IsCropPossible(ref Rectangle cropRectangle)
- {
- cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height);
- if (cropRectangle.Left < 0)
- {
- cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height);
- }
-
- if (cropRectangle.Top < 0)
- {
- cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top);
- }
-
- if (cropRectangle.Left + cropRectangle.Width > Image.Width)
- {
- cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height);
- }
-
- if (cropRectangle.Top + cropRectangle.Height > Image.Height)
- {
- cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top);
- }
-
- if (cropRectangle.Height > 0 && cropRectangle.Width > 0)
- {
- return true;
- }
-
- return false;
- }
-
- ///
- /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area
- ///
- /// Who send
- /// Type of message
- /// Message itself
- public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message)
- {
- if (_surfaceMessage != null)
- {
- var eventArgs = new SurfaceMessageEventArgs
- {
- Message = message,
- MessageType = messageType,
- Surface = this
- };
- _surfaceMessage(source, eventArgs);
- }
- }
-
- ///
- /// Crop the surface
- ///
- ///
- ///
- public bool ApplyCrop(Rectangle cropRectangle)
- {
- if (IsCropPossible(ref cropRectangle))
- {
- Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
- Bitmap tmpImage;
- // Make sure we have information, this this fails
- try
- {
- 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;
- }
-
- return false;
- }
-
- ///
- /// The background here is the captured image.
- /// This is called from the SurfaceBackgroundChangeMemento.
- ///
- ///
- ///
- public void UndoBackgroundChange(Image previous, Matrix matrix)
- {
- SetImage(previous, false);
- if (matrix != null)
- {
- _elements.Transform(matrix);
- }
-
- _surfaceSizeChanged?.Invoke(this, null);
- Invalidate();
- }
-
- ///
- /// Check if an adorner was "hit", and change the cursor if so
- ///
- /// MouseEventArgs
- /// IAdorner
- private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs)
- {
- foreach (IDrawableContainer drawableContainer in selectedElements)
- {
- foreach (IAdorner adorner in drawableContainer.Adorners)
- {
- if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location))
- {
- if (adorner.Cursor != null)
- {
- Cursor = adorner.Cursor;
- }
-
- return adorner;
- }
- }
- }
-
- return null;
- }
-
- ///
- /// Translate mouse coordinates as if they were applied directly to unscaled image.
- ///
- private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e)
- => new MouseEventArgs(e.Button, e.Clicks, (int) (e.X / _zoomFactor), (int) (e.Y / _zoomFactor), e.Delta);
-
- ///
- /// This event handler is called when someone presses the mouse on a surface.
- ///
- ///
- ///
- private void SurfaceMouseDown(object sender, MouseEventArgs e)
- {
- e = InverseZoomMouseCoordinates(e);
-
- // Handle Adorners
- var adorner = FindActiveAdorner(e);
- if (adorner != null)
- {
- adorner.MouseDown(sender, e);
- return;
- }
-
- _mouseStart = e.Location;
-
- // check contextmenu
- if (e.Button == MouseButtons.Right)
- {
- IDrawableContainerList selectedList = null;
- if (selectedElements != null && selectedElements.Count > 0)
- {
- selectedList = selectedElements;
- }
- else
- {
- // Single element
- IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y);
- if (rightClickedContainer != null)
- {
- selectedList = new DrawableContainerList(ID)
- {
- rightClickedContainer
- };
- }
- }
-
- if (selectedList != null && selectedList.Count > 0)
- {
- selectedList.ShowContextMenu(e, this);
- }
-
- return;
- }
-
- _mouseDown = true;
- _isSurfaceMoveMadeUndoable = false;
-
- if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop)))
- {
- RemoveElement(_cropContainer, false);
- _cropContainer = null;
- _drawingElement = null;
- }
-
- if (_drawingElement == null && DrawingMode != DrawingModes.None)
- {
- if (_undrawnElement == null)
- {
- DeselectAllElements();
- if (_undrawnElement == null)
- {
- CreateUndrawnElement();
- }
- }
-
- _drawingElement = _undrawnElement;
- // if a new element has been drawn, set location and register it
- if (_drawingElement != null)
- {
- if (_undrawnElement != null)
- {
- _drawingElement.Status = _undrawnElement.DefaultEditMode;
- }
-
- if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y))
- {
- _drawingElement.Left = _mouseStart.X;
- _drawingElement.Top = _mouseStart.Y;
- }
-
- AddElement(_drawingElement);
- _drawingElement.Selected = true;
- }
-
- _undrawnElement = null;
- }
- else
- {
- // check whether an existing element was clicked
- // we save mouse down element separately from selectedElements (checked on mouse up),
- // since it could be moved around before it is actually selected
- _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y);
-
- if (_mouseDownElement != null)
- {
- _mouseDownElement.Status = EditStatus.MOVING;
- }
- }
- }
-
- ///
- /// This event handle is called when the mouse button is unpressed
- ///
- ///
- ///
- private void SurfaceMouseUp(object sender, MouseEventArgs e)
- {
- e = InverseZoomMouseCoordinates(e);
-
- // Handle Adorners
- var adorner = FindActiveAdorner(e);
- if (adorner != null)
- {
- adorner.MouseUp(sender, e);
- return;
- }
-
- Point currentMouse = new Point(e.X, e.Y);
-
- _elements.Status = EditStatus.IDLE;
- if (_mouseDownElement != null)
- {
- _mouseDownElement.Status = EditStatus.IDLE;
- }
-
- _mouseDown = false;
- _mouseDownElement = null;
- if (DrawingMode == DrawingModes.None)
- {
- // check whether an existing element was clicked
- IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y);
- bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift;
- if (element != null)
- {
- element.Invalidate();
- bool alreadySelected = selectedElements.Contains(element);
- if (shiftModifier)
- {
- if (alreadySelected)
- {
- DeselectElement(element);
- }
- else
- {
- SelectElement(element);
- }
- }
- else
- {
- if (!alreadySelected)
- {
- DeselectAllElements();
- SelectElement(element);
- }
- }
- }
- else if (!shiftModifier)
- {
- DeselectAllElements();
- }
- }
-
- if (selectedElements.Count > 0)
- {
- selectedElements.Invalidate();
- selectedElements.Selected = true;
- }
-
- if (_drawingElement != null)
- {
- if (!_drawingElement.InitContent())
- {
- _elements.Remove(_drawingElement);
- _drawingElement.Invalidate();
- }
- else
- {
- _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y);
- _drawingElement.Invalidate();
- if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5)
- {
- _drawingElement.Width = 25;
- _drawingElement.Height = 25;
- }
-
- SelectElement(_drawingElement);
- _drawingElement.Selected = true;
- }
-
- _drawingElement = null;
- }
- }
-
- ///
- /// This event handler is called when the mouse moves over the surface
- ///
- ///
- ///
- private void SurfaceMouseMove(object sender, MouseEventArgs e)
- {
- e = InverseZoomMouseCoordinates(e);
-
- // Handle Adorners
- var adorner = FindActiveAdorner(e);
- if (adorner != null)
- {
- adorner.MouseMove(sender, e);
- return;
- }
-
- Point currentMouse = e.Location;
-
- Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default;
-
- if (_mouseDown)
- {
- if (_mouseDownElement != null)
- {
- // an element is currently dragged
- _mouseDownElement.Invalidate();
- selectedElements.Invalidate();
- // Move the element
- if (_mouseDownElement.Selected)
- {
- if (!_isSurfaceMoveMadeUndoable)
- {
- // Only allow one undoable per mouse-down/move/up "cycle"
- _isSurfaceMoveMadeUndoable = true;
- selectedElements.MakeBoundsChangeUndoable(false);
- }
-
- // dragged element has been selected before -> move all
- selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y);
- }
- else
- {
- if (!_isSurfaceMoveMadeUndoable)
- {
- // 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;
- }
- }
- }
-
- ///
- /// This event handler is called when the surface is double clicked.
- ///
- ///
- ///
- private void SurfaceDoubleClick(object sender, MouseEventArgs e)
- {
- selectedElements.OnDoubleClick();
- selectedElements.Invalidate();
- }
-
- ///
- /// Privately used to get the rendered image with all the elements on it.
- ///
- ///
- ///
- private Image GetImage(RenderMode renderMode)
- {
- // Generate a copy of the original image with a dpi equal to the default...
- Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare);
- // otherwise we would have a problem drawing the image to the surface... :(
- using (Graphics graphics = Graphics.FromImage(clone))
- {
- // Do not set the following, the containers need to decide themselves
- //graphics.SmoothingMode = SmoothingMode.HighQuality;
- //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
- //graphics.CompositingQuality = CompositingQuality.HighQuality;
- //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- _elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size));
- }
-
- return clone;
- }
-
- ///
- /// This returns the image "result" of this surface, with all the elements rendered on it.
- ///
- ///
- public Image GetImageForExport()
- {
- 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));
-
- ///
- /// This is the event handler for the Paint Event, try to draw as little as possible!
- ///
- ///
- /// PaintEventArgs
- private void SurfacePaint(object sender, PaintEventArgs paintEventArgs)
- {
- Graphics targetGraphics = paintEventArgs.Graphics;
- Rectangle targetClipRectangle = paintEventArgs.ClipRectangle;
- if (Rectangle.Empty.Equals(targetClipRectangle))
- {
- LOG.Debug("Empty cliprectangle??");
- return;
- }
-
- // 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.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat)
- {
- _buffer.Dispose();
- _buffer = null;
- }
- }
-
- if (_buffer == null)
- {
- _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution);
- LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height);
- }
-
- // Elements might need the bitmap, so we copy the part we need
- using (Graphics graphics = Graphics.FromImage(_buffer))
- {
- // do not set the following, the containers need to decide this themselves!
- //graphics.SmoothingMode = SmoothingMode.HighQuality;
- //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
- //graphics.CompositingQuality = CompositingQuality.HighQuality;
- //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- DrawBackground(graphics, imageClipRectangle);
- graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
- graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2));
- _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();
- }
- }
- else
- {
- DrawBackground(targetGraphics, targetClipRectangle);
- if (_zoomFactor == Fraction.Identity)
- {
- 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
- targetGraphics.ResetClip();
- // Draw adorners last
- foreach (var drawableContainer in selectedElements)
- {
- foreach (var adorner in drawableContainer.Adorners)
- {
- adorner.Paint(paintEventArgs);
- }
- }
- }
-
- 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)
- {
- // check if we need to draw the checkerboard
- if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null)
- {
- targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle);
- }
- else
- {
- targetGraphics.Clear(BackColor);
- }
- }
-
- ///
- /// Draw a checkboard when capturing with transparency
- ///
- /// PaintEventArgs
- protected override void OnPaintBackground(PaintEventArgs e)
- {
- }
-
- ///
- /// Add a new element to the surface
- ///
- /// the new element
- /// true if the adding should be undoable
- /// true if invalidate needs to be called
- public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true)
- {
- _elements.Add(element);
- if (element is DrawableContainer container)
- {
- container.FieldChanged += Element_FieldChanged;
- }
-
- element.Parent = this;
- if (element.Status == EditStatus.UNDRAWN)
- {
- element.Status = EditStatus.IDLE;
- }
-
- if (element.Selected)
- {
- // Use false, as the element is invalidated when invalidate == true anyway
- SelectElement(element, false);
- }
-
- if (invalidate)
- {
- element.Invalidate();
- }
-
- if (makeUndoable)
- {
- MakeUndoable(new AddElementMemento(this, element), false);
- }
-
- _modified = true;
- }
-
- ///
- /// Remove the list of elements
- ///
- /// IDrawableContainerList
- /// flag specifying if the remove needs to be undoable
- public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true)
- {
- // fix potential issues with iterating a changing list
- DrawableContainerList cloned = new DrawableContainerList();
- cloned.AddRange(elementsToRemove);
- if (makeUndoable)
- {
- MakeUndoable(new DeleteElementsMemento(this, cloned), false);
- }
-
- SuspendLayout();
- foreach (var drawableContainer in cloned)
- {
- RemoveElement(drawableContainer, false, false, false);
- }
-
- ResumeLayout();
- Invalidate();
- if (_movingElementChanged != null)
- {
- SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
- {
- Elements = cloned
- };
- _movingElementChanged(this, eventArgs);
- }
- }
-
- ///
- /// Remove an element of the elements list
- ///
- /// Element to remove
- /// flag specifying if the remove needs to be undoable
- /// flag specifying if an surface invalidate needs to be called
- /// false to skip event generation
- public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true)
- {
- DeselectElement(elementToRemove, generateEvents);
- _elements.Remove(elementToRemove);
- if (elementToRemove is DrawableContainer element)
- {
- element.FieldChanged -= Element_FieldChanged;
- }
-
- if (elementToRemove != null)
- {
- elementToRemove.Parent = null;
- }
-
- // Do not dispose, the memento should!! element.Dispose();
- if (invalidate)
- {
- Invalidate();
- }
-
- if (makeUndoable)
- {
- MakeUndoable(new DeleteElementMemento(this, elementToRemove), false);
- }
-
- _modified = true;
- }
-
- ///
- /// Add the supplied elements to the surface
- ///
- /// DrawableContainerList
- /// true if the adding should be undoable
- public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true)
- {
- // fix potential issues with iterating a changing list
- DrawableContainerList cloned = new DrawableContainerList();
- cloned.AddRange(elementsToAdd);
- if (makeUndoable)
- {
- MakeUndoable(new AddElementsMemento(this, cloned), false);
- }
-
- SuspendLayout();
- foreach (var element in cloned)
- {
- element.Selected = true;
- AddElement(element, false, false);
- }
-
- ResumeLayout();
- Invalidate();
- }
-
- ///
- /// Returns if this surface has selected elements
- ///
- ///
- public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0);
-
- ///
- /// Remove all the selected elements
- ///
- public void RemoveSelectedElements()
- {
- if (HasSelectedElements)
- {
- // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list.
- RemoveElements(selectedElements);
- if (_movingElementChanged != null)
- {
- SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs();
- _movingElementChanged(this, eventArgs);
- }
- }
- }
-
- ///
- /// Cut the selected elements from the surface to the clipboard
- ///
- public void CutSelectedElements()
- {
- if (HasSelectedElements)
- {
- ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
- RemoveSelectedElements();
- }
- }
-
- ///
- /// Copy the selected elements to the clipboard
- ///
- public void CopySelectedElements()
- {
- if (HasSelectedElements)
- {
- ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
- }
- }
-
- ///
- /// This method is called to confirm/cancel "confirmable" elements, like the crop-container.
- /// Called when pressing enter or using the "check" in the editor.
- ///
- ///
- public void ConfirmSelectedConfirmableElements(bool confirm)
- {
- // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel)
- List selectedDCs = new List(selectedElements);
- foreach (IDrawableContainer dc in selectedDCs)
- {
- if (dc.Equals(_cropContainer))
- {
- DrawingMode = DrawingModes.None;
- // No undo memento for the cropcontainer itself, only for the effect
- RemoveElement(_cropContainer, false);
- if (confirm)
- {
- ApplyCrop(_cropContainer.Bounds);
- }
-
- _cropContainer.Dispose();
- _cropContainer = null;
- break;
- }
- }
- }
-
- ///
- /// Paste all the elements that are on the clipboard
- ///
- public void PasteElementFromClipboard()
- {
- IDataObject clipboard = ClipboardHelper.GetDataObject();
-
- var formats = ClipboardHelper.GetFormats(clipboard);
- if (formats == null || formats.Count == 0)
- {
- return;
- }
-
- if (LOG.IsDebugEnabled)
- {
- LOG.Debug("List of clipboard formats available for pasting:");
- foreach (string format in formats)
- {
- LOG.Debug("\tgot format: " + format);
- }
- }
-
- if (formats.Contains(typeof(IDrawableContainerList).FullName))
- {
- IDrawableContainerList dcs = (IDrawableContainerList) ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList));
- if (dcs != null)
- {
- // Make element(s) only move 10,10 if the surface is the same
- bool isSameSurface = (dcs.ParentID == _uniqueId);
- dcs.Parent = this;
- var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty;
- // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList
- Rectangle drawableContainerListBounds = Rectangle.Empty;
- foreach (var element in dcs)
- {
- drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty
- ? element.DrawingBounds
- : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds);
- }
-
- // And find a location inside the target surface to paste to
- bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height;
- if (!containersCanFit)
- {
- Point containersLocation = drawableContainerListBounds.Location;
- containersLocation.Offset(moveOffset);
- if (!Bounds.Contains(containersLocation))
- {
- // Easy fix for same surface
- moveOffset = isSameSurface
- ? new Point(-10, -10)
- : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10);
- }
- }
- else
- {
- Rectangle moveContainerListBounds = drawableContainerListBounds;
- moveContainerListBounds.Offset(moveOffset);
- // check if the element is inside
- if (!Bounds.Contains(moveContainerListBounds))
- {
- // Easy fix for same surface
- if (isSameSurface)
- {
- moveOffset = new Point(-10, -10);
- }
- else
- {
- // For different surface, which is most likely smaller
- int offsetX = 0;
- int offsetY = 0;
- if (drawableContainerListBounds.Right > Bounds.Right)
- {
- offsetX = Bounds.Right - drawableContainerListBounds.Right;
- // Correction for the correction
- if (drawableContainerListBounds.Left + offsetX < 0)
- {
- offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX);
- }
- }
-
- if (drawableContainerListBounds.Bottom > Bounds.Bottom)
- {
- offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom;
- // Correction for the correction
- if (drawableContainerListBounds.Top + offsetY < 0)
- {
- offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY);
- }
- }
-
- moveOffset = new Point(offsetX, offsetY);
- }
- }
- }
-
- dcs.MoveBy(moveOffset.X, moveOffset.Y);
- AddElements(dcs);
- FieldAggregator.BindElements(dcs);
- DeselectAllElements();
- SelectElements(dcs);
- }
- }
- else if (ClipboardHelper.ContainsImage(clipboard))
- {
- Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
-
- foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard))
- {
- if (clipboardImage != null)
- {
- DeselectAllElements();
- IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y);
- SelectElement(container);
- clipboardImage.Dispose();
- pasteLocation.X += 10;
- pasteLocation.Y += 10;
- }
- }
- }
- else if (ClipboardHelper.ContainsText(clipboard))
- {
- Point pasteLocation = GetPasteLocation(0.4f, 0.4f);
-
- string text = ClipboardHelper.GetText(clipboard);
- if (text != null)
- {
- DeselectAllElements();
- ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y,
- FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent);
- SelectElement(textContainer);
- }
- }
- }
-
- ///
- /// 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.
- ///
- /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area.
- /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area.
- 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);
- }
-
- ///
- /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space).
- ///
- 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
- );
- }
-
- ///
- /// Get the rectangle bounding all selected elements (in surface coordinates space),
- /// or empty rectangle if nothing is selcted.
- ///
- public Rectangle GetSelectionRectangle()
- => ToSurfaceCoordinates(selectedElements.DrawingBounds);
-
- ///
- /// Duplicate all the selecteded elements
- ///
- public void DuplicateSelectedElements()
- {
- LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count);
- IDrawableContainerList dcs = selectedElements.Clone();
- dcs.Parent = this;
- dcs.MoveBy(10, 10);
- AddElements(dcs);
- DeselectAllElements();
- SelectElements(dcs);
- }
-
- ///
- /// Deselect the specified element
- ///
- /// IDrawableContainerList
- /// false to skip event generation
- public void DeselectElement(IDrawableContainer container, bool generateEvents = true)
- {
- container.Selected = false;
- selectedElements.Remove(container);
- FieldAggregator.UnbindElement(container);
- if (generateEvents && _movingElementChanged != null)
- {
- var eventArgs = new SurfaceElementEventArgs
- {
- Elements = selectedElements
- };
- _movingElementChanged(this, eventArgs);
- }
- }
-
- ///
- /// Deselect the specified elements
- ///
- /// IDrawableContainerList
- public void DeselectElements(IDrawableContainerList elements)
- {
- if (elements.Count == 0)
- {
- return;
- }
-
- while (elements.Count > 0)
- {
- var element = elements[0];
- DeselectElement(element, false);
- }
-
- if (_movingElementChanged != null)
- {
- SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
- {
- Elements = selectedElements
- };
- _movingElementChanged(this, eventArgs);
- }
-
- Invalidate();
- }
-
- ///
- /// Deselect all the selected elements
- ///
- public void DeselectAllElements()
- {
- DeselectElements(selectedElements);
- }
-
- ///
- /// Select the supplied element
- ///
- ///
- /// false to skip invalidation
- /// false to skip event generation
- public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true)
- {
- if (!selectedElements.Contains(container))
- {
- selectedElements.Add(container);
- container.Selected = true;
- FieldAggregator.BindElement(container);
- if (generateEvents && _movingElementChanged != null)
- {
- SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
- {
- Elements = selectedElements
- };
- _movingElementChanged(this, eventArgs);
- }
-
- if (invalidate)
- {
- container.Invalidate();
- }
- }
- }
-
- ///
- /// Select all elements, this is called when Ctrl+A is pressed
- ///
- public void SelectAllElements()
- {
- SelectElements(_elements);
- }
-
- ///
- /// Select the supplied elements
- ///
- ///
- public void SelectElements(IDrawableContainerList elements)
- {
- SuspendLayout();
- foreach (var drawableContainer in elements)
- {
- var element = (DrawableContainer) drawableContainer;
- SelectElement(element, false, false);
- }
-
- if (_movingElementChanged != null)
- {
- SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
- {
- Elements = selectedElements
- };
- _movingElementChanged(this, eventArgs);
- }
-
- ResumeLayout();
- Invalidate();
- }
-
- ///
- /// Process key presses on the surface, this is called from the editor (and NOT an override from the Control)
- ///
- /// Keys
- /// false if no keys were processed
- public bool ProcessCmdKey(Keys k)
- {
- if (selectedElements.Count > 0)
- {
- bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift;
- int px = shiftModifier ? 10 : 1;
- Point moveBy = Point.Empty;
-
- switch (k)
- {
- case Keys.Left:
- case Keys.Left | Keys.Shift:
- moveBy = new Point(-px, 0);
- break;
- case Keys.Up:
- case Keys.Up | Keys.Shift:
- moveBy = new Point(0, -px);
- break;
- case Keys.Right:
- case Keys.Right | Keys.Shift:
- moveBy = new Point(px, 0);
- break;
- case Keys.Down:
- case Keys.Down | Keys.Shift:
- moveBy = new Point(0, px);
- break;
- case Keys.PageUp:
- PullElementsUp();
- break;
- case Keys.PageDown:
- PushElementsDown();
- break;
- case Keys.Home:
- PullElementsToTop();
- break;
- case Keys.End:
- PushElementsToBottom();
- break;
- case Keys.Enter:
- ConfirmSelectedConfirmableElements(true);
- break;
- case Keys.Escape:
- ConfirmSelectedConfirmableElements(false);
- break;
- /*case Keys.Delete:
- RemoveSelectedElements();
- break;*/
- default:
- return false;
- }
-
- if (!Point.Empty.Equals(moveBy))
- {
- selectedElements.MakeBoundsChangeUndoable(true);
- selectedElements.MoveBy(moveBy.X, moveBy.Y);
- }
-
- return true;
- }
-
- return false;
- }
-
- ///
- /// Property for accessing the elements on the surface
- ///
- public IDrawableContainerList Elements => _elements;
-
- ///
- /// pulls selected elements up one level in hierarchy
- ///
- public void PullElementsUp()
- {
- _elements.PullElementsUp(selectedElements);
- _elements.Invalidate();
- }
-
- ///
- /// pushes selected elements up to top in hierarchy
- ///
- public void PullElementsToTop()
- {
- _elements.PullElementsToTop(selectedElements);
- _elements.Invalidate();
- }
-
- ///
- /// pushes selected elements down one level in hierarchy
- ///
- public void PushElementsDown()
- {
- _elements.PushElementsDown(selectedElements);
- _elements.Invalidate();
- }
-
- ///
- /// pushes selected elements down to bottom in hierarchy
- ///
- public void PushElementsToBottom()
- {
- _elements.PushElementsToBottom(selectedElements);
- _elements.Invalidate();
- }
-
- ///
- /// indicates whether the selected elements could be pulled up in hierarchy
- ///
- /// true if selected elements could be pulled up, false otherwise
- public bool CanPullSelectionUp()
- {
- return _elements.CanPullUp(selectedElements);
- }
-
- ///
- /// indicates whether the selected elements could be pushed down in hierarchy
- ///
- /// true if selected elements could be pushed down, false otherwise
- public bool CanPushSelectionDown()
- {
- return _elements.CanPushDown(selectedElements);
- }
-
- public void Element_FieldChanged(object sender, FieldChangedEventArgs e)
- {
- selectedElements.HandleFieldChangedEvent(sender, e);
- }
-
- public bool IsOnSurface(IDrawableContainer 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
- );
- }
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Windows.Forms;
+using Greenshot.Base.Controls;
+using Greenshot.Base.Core;
+using Greenshot.Base.Effects;
+using Greenshot.Base.IniFile;
+using Greenshot.Base.Interfaces;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Base.Interfaces.Drawing.Adorners;
+using Greenshot.Editor.Configuration;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+using Greenshot.Editor.Memento;
+using log4net;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Description of Surface.
+ ///
+ public sealed class Surface : Control, ISurface, INotifyPropertyChanged
+ {
+ private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface));
+ public static int Count;
+ private static readonly CoreConfiguration conf = IniConfig.GetIniSection();
+
+ // Property to identify the Surface ID
+ private Guid _uniqueId = Guid.NewGuid();
+
+ ///
+ /// This value is used to start counting the step labels
+ ///
+ private int _counterStart = 1;
+
+ ///
+ /// The GUID of the surface
+ ///
+ public Guid ID
+ {
+ get => _uniqueId;
+ set => _uniqueId = value;
+ }
+
+ ///
+ /// Event handlers (do not serialize!)
+ ///
+ [NonSerialized] private PropertyChangedEventHandler _propertyChanged;
+
+ public event PropertyChangedEventHandler PropertyChanged
+ {
+ add => _propertyChanged += value;
+ remove => _propertyChanged -= value;
+ }
+
+ [NonSerialized] private SurfaceElementEventHandler _movingElementChanged;
+
+ public event SurfaceElementEventHandler MovingElementChanged
+ {
+ add => _movingElementChanged += value;
+ remove => _movingElementChanged -= value;
+ }
+
+ [NonSerialized] private SurfaceDrawingModeEventHandler _drawingModeChanged;
+
+ public event SurfaceDrawingModeEventHandler DrawingModeChanged
+ {
+ add => _drawingModeChanged += value;
+ remove => _drawingModeChanged -= value;
+ }
+
+ [NonSerialized] private SurfaceSizeChangeEventHandler _surfaceSizeChanged;
+
+ public event SurfaceSizeChangeEventHandler SurfaceSizeChanged
+ {
+ add => _surfaceSizeChanged += value;
+ remove => _surfaceSizeChanged -= value;
+ }
+
+ [NonSerialized] private SurfaceMessageEventHandler _surfaceMessage;
+
+ public event SurfaceMessageEventHandler SurfaceMessage
+ {
+ add => _surfaceMessage += value;
+ remove => _surfaceMessage -= value;
+ }
+
+ ///
+ /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action
+ ///
+ [NonSerialized] private bool _inUndoRedo;
+
+ ///
+ /// Make only one surface move cycle undoable, see SurfaceMouseMove
+ ///
+ [NonSerialized] private bool _isSurfaceMoveMadeUndoable;
+
+ ///
+ /// Undo/Redo stacks, should not be serialized as the file would be way to big
+ ///
+ [NonSerialized] private readonly Stack _undoStack = new Stack();
+
+ [NonSerialized] private readonly Stack _redoStack = new Stack();
+
+ ///
+ /// Last save location, do not serialize!
+ ///
+ [NonSerialized] private string _lastSaveFullPath;
+
+ ///
+ /// current drawing mode, do not serialize!
+ ///
+ [NonSerialized] private DrawingModes _drawingMode = DrawingModes.None;
+
+ ///
+ /// the keys-locked flag helps with focus issues
+ ///
+ [NonSerialized] private bool _keysLocked;
+
+ ///
+ /// Location of the mouse-down (it "starts" here), do not serialize
+ ///
+ [NonSerialized] private Point _mouseStart = Point.Empty;
+
+ ///
+ /// are we in a mouse down, do not serialize
+ ///
+ [NonSerialized] private bool _mouseDown;
+
+ ///
+ /// The selected element for the mouse down, do not serialize
+ ///
+ [NonSerialized] private IDrawableContainer _mouseDownElement;
+
+ ///
+ /// all selected elements, do not serialize
+ ///
+ [NonSerialized] private readonly IDrawableContainerList selectedElements;
+
+ ///
+ /// the element we are drawing with, do not serialize
+ ///
+ [NonSerialized] private IDrawableContainer _drawingElement;
+
+ ///
+ /// the element we want to draw with (not yet drawn), do not serialize
+ ///
+ [NonSerialized] private IDrawableContainer _undrawnElement;
+
+ ///
+ /// the cropcontainer, when cropping this is set, do not serialize
+ ///
+ [NonSerialized] private IDrawableContainer _cropContainer;
+
+ ///
+ /// the brush which is used for transparent backgrounds, set by the editor, do not serialize
+ ///
+ [NonSerialized] private Brush _transparencyBackgroundBrush;
+
+ ///
+ /// The buffer is only for drawing on it when using filters (to supply access)
+ /// This saves a lot of "create new bitmap" commands
+ /// Should not be serialized, as it's generated.
+ /// The actual bitmap is in the paintbox...
+ /// TODO: Check if this buffer is still needed!
+ ///
+ [NonSerialized] private Bitmap _buffer;
+
+ ///
+ /// all stepLabels for the surface, needed with serialization
+ ///
+ private readonly List _stepLabels = new List();
+
+ public void AddStepLabel(StepLabelContainer stepLabel)
+ {
+ if (!_stepLabels.Contains(stepLabel))
+ {
+ _stepLabels.Add(stepLabel);
+ }
+ }
+
+ public void RemoveStepLabel(StepLabelContainer stepLabel)
+ {
+ _stepLabels.Remove(stepLabel);
+ }
+
+ ///
+ /// The start value of the counter objects
+ ///
+ public int CounterStart
+ {
+ get => _counterStart;
+ set
+ {
+ if (_counterStart == value)
+ {
+ return;
+ }
+
+ _counterStart = value;
+ Invalidate();
+ _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CounterStart)));
+ }
+ }
+
+ ///
+ /// Count all the VISIBLE steplabels in the surface, up to the supplied one
+ ///
+ /// can be null, if not the counting stops here
+ /// number of steplabels before the supplied container
+ public int CountStepLabels(IDrawableContainer stopAtContainer)
+ {
+ int number = CounterStart;
+ foreach (var possibleThis in _stepLabels)
+ {
+ if (possibleThis.Equals(stopAtContainer))
+ {
+ break;
+ }
+
+ if (IsOnSurface(possibleThis))
+ {
+ number++;
+ }
+ }
+
+ return number;
+ }
+
+ ///
+ /// all elements on the surface, needed with serialization
+ ///
+ private readonly IDrawableContainerList _elements;
+
+ ///
+ /// all elements on the surface, needed with serialization
+ ///
+ private FieldAggregator _fieldAggregator;
+
+ ///
+ /// the cursor container, needed with serialization as we need a direct acces to it.
+ ///
+ private IDrawableContainer _cursorContainer;
+
+ ///
+ /// the modified flag specifies if the surface has had modifications after the last export.
+ /// Initial state is modified, as "it's not saved"
+ /// After serialization this should actually be "false" (the surface came from a stream)
+ /// For now we just serialize it...
+ ///
+ private bool _modified = true;
+
+ ///
+ /// The image is the actual captured image, needed with serialization
+ ///
+ private Image _image;
+
+ public Image Image
+ {
+ get => _image;
+ set
+ {
+ _image = value;
+ 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();
+ }
+ }
+
+
+ ///
+ /// Sets the surface size as zoomed image size.
+ ///
+ private void UpdateSize()
+ {
+ var size = _image.Size;
+ Size = new Size((int) (size.Width * _zoomFactor), (int) (size.Height * _zoomFactor));
+ }
+
+ ///
+ /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements.
+ /// e.g. used to decided if and which line thickness is shown when multiple elements are selected.
+ ///
+ public FieldAggregator FieldAggregator
+ {
+ get => _fieldAggregator;
+ set => _fieldAggregator = value;
+ }
+
+ ///
+ /// The cursor container has it's own accessor so we can find and remove this (when needed)
+ ///
+ public IDrawableContainer CursorContainer => _cursorContainer;
+
+ ///
+ /// A simple getter to ask if this surface has a cursor
+ ///
+ public bool HasCursor => _cursorContainer != null;
+
+ ///
+ /// A simple helper method to remove the cursor from the surface
+ ///
+ public void RemoveCursor()
+ {
+ RemoveElement(_cursorContainer);
+ _cursorContainer = null;
+ }
+
+ ///
+ /// The brush which is used to draw the transparent background
+ ///
+ public Brush TransparencyBackgroundBrush
+ {
+ get => _transparencyBackgroundBrush;
+ set => _transparencyBackgroundBrush = value;
+ }
+
+ ///
+ /// Are the keys on this surface locked?
+ ///
+ public bool KeysLocked
+ {
+ get => _keysLocked;
+ set => _keysLocked = value;
+ }
+
+ ///
+ /// Is this surface modified? This is only true if the surface has not been exported.
+ ///
+ public bool Modified
+ {
+ get => _modified;
+ set => _modified = value;
+ }
+
+ ///
+ /// The DrawingMode property specifies the mode for drawing, more or less the element type.
+ ///
+ public DrawingModes DrawingMode
+ {
+ get => _drawingMode;
+ set
+ {
+ _drawingMode = value;
+ if (_drawingModeChanged != null)
+ {
+ SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs
+ {
+ DrawingMode = _drawingMode
+ };
+ _drawingModeChanged.Invoke(this, eventArgs);
+ }
+
+ DeselectAllElements();
+ CreateUndrawnElement();
+ }
+ }
+
+ ///
+ /// Property for accessing the last save "full" path
+ ///
+ public string LastSaveFullPath
+ {
+ get => _lastSaveFullPath;
+ set => _lastSaveFullPath = value;
+ }
+
+ ///
+ /// Property for accessing the URL to which the surface was recently uploaded
+ ///
+ public string UploadUrl { get; set; }
+
+ ///
+ /// Property for accessing the capture details
+ ///
+ public ICaptureDetails CaptureDetails { get; set; }
+
+ ///
+ /// Adjust UI elements to the supplied DPI settings
+ ///
+ ///
+ public void AdjustToDpi(uint dpi)
+ {
+ foreach (var element in this._elements)
+ {
+ element.AdjustToDpi(dpi);
+ }
+ }
+
+ ///
+ /// Base Surface constructor
+ ///
+ public Surface()
+ {
+ _fieldAggregator = new FieldAggregator(this);
+ Count++;
+ _elements = new DrawableContainerList(_uniqueId);
+ selectedElements = new DrawableContainerList(_uniqueId);
+ LOG.Debug("Creating surface!");
+ MouseDown += SurfaceMouseDown;
+ MouseUp += SurfaceMouseUp;
+ MouseMove += SurfaceMouseMove;
+ MouseDoubleClick += SurfaceDoubleClick;
+ Paint += SurfacePaint;
+ AllowDrop = true;
+ DragDrop += OnDragDrop;
+ DragEnter += OnDragEnter;
+ // bind selected & elements to this, otherwise they can't inform of modifications
+ selectedElements.Parent = this;
+ _elements.Parent = this;
+ // Make sure we are visible
+ Visible = true;
+ TabStop = false;
+ // Enable double buffering
+ DoubleBuffered = true;
+ SetStyle(
+ ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer |
+ ControlStyles.SupportsTransparentBackColor, true);
+ }
+
+ ///
+ /// Private method, the current image is disposed the new one will stay.
+ ///
+ /// The new image
+ /// true if the old image needs to be disposed, when using undo this should not be true!!
+ private void SetImage(Image newImage, bool dispose)
+ {
+ // Dispose
+ if (_image != null && dispose)
+ {
+ _image.Dispose();
+ }
+
+ // Set new values
+ Image = newImage;
+
+ _modified = true;
+ }
+
+ ///
+ /// Surface constructor with an image
+ ///
+ ///
+ public Surface(Image newImage) : this()
+ {
+ LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat);
+ SetImage(newImage, true);
+ }
+
+ ///
+ /// Surface contructor with a capture
+ ///
+ ///
+ public Surface(ICapture capture) : this(capture.Image)
+ {
+ // check if cursor is captured, and visible
+ if (capture.Cursor != null && capture.CursorVisible)
+ {
+ Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size);
+ Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size);
+ // check if cursor is on the capture, otherwise we leave it out.
+ if (cursorRect.IntersectsWith(captureRect))
+ {
+ _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y);
+ SelectElement(_cursorContainer);
+ }
+ }
+
+ // Make sure the image is NOT disposed, we took the reference directly into ourselves
+ ((Capture) capture).NullImage();
+
+ CaptureDetails = capture.CaptureDetails;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Count--;
+ LOG.Debug("Disposing surface!");
+ if (_buffer != null)
+ {
+ _buffer.Dispose();
+ _buffer = null;
+ }
+
+ if (_transparencyBackgroundBrush != null)
+ {
+ _transparencyBackgroundBrush.Dispose();
+ _transparencyBackgroundBrush = null;
+ }
+
+ // Cleanup undo/redo stacks
+ while (_undoStack != null && _undoStack.Count > 0)
+ {
+ _undoStack.Pop().Dispose();
+ }
+
+ while (_redoStack != null && _redoStack.Count > 0)
+ {
+ _redoStack.Pop().Dispose();
+ }
+
+ foreach (IDrawableContainer container in _elements)
+ {
+ container.Dispose();
+ }
+
+ if (_undrawnElement != null)
+ {
+ _undrawnElement.Dispose();
+ _undrawnElement = null;
+ }
+
+ if (_cropContainer != null)
+ {
+ _cropContainer.Dispose();
+ _cropContainer = null;
+ }
+ }
+
+ base.Dispose(disposing);
+ }
+
+ ///
+ /// Undo the last action
+ ///
+ public void Undo()
+ {
+ if (_undoStack.Count > 0)
+ {
+ _inUndoRedo = true;
+ IMemento top = _undoStack.Pop();
+ _redoStack.Push(top.Restore());
+ _inUndoRedo = false;
+ }
+ }
+
+ ///
+ /// Undo an undo (=redo)
+ ///
+ public void Redo()
+ {
+ if (_redoStack.Count > 0)
+ {
+ _inUndoRedo = true;
+ IMemento top = _redoStack.Pop();
+ _undoStack.Push(top.Restore());
+ _inUndoRedo = false;
+ }
+ }
+
+ ///
+ /// Returns if the surface can do a undo
+ ///
+ public bool CanUndo => _undoStack.Count > 0;
+
+ ///
+ /// Returns if the surface can do a redo
+ ///
+ public bool CanRedo => _redoStack.Count > 0;
+
+ ///
+ /// Get the language key for the undo action
+ ///
+ public LangKey UndoActionLanguageKey => LangKey.none;
+
+ ///
+ /// Get the language key for redo action
+ ///
+ public LangKey RedoActionLanguageKey => LangKey.none;
+
+ ///
+ /// Make an action undo-able
+ ///
+ /// The memento implementing the undo
+ /// Allow changes to be merged
+ public void MakeUndoable(IMemento memento, bool allowMerge)
+ {
+ if (_inUndoRedo)
+ {
+ throw new InvalidOperationException("Invoking do within an undo/redo action.");
+ }
+
+ if (memento != null)
+ {
+ bool allowPush = true;
+ if (_undoStack.Count > 0 && allowMerge)
+ {
+ // Check if merge is possible
+ allowPush = !_undoStack.Peek().Merge(memento);
+ }
+
+ if (allowPush)
+ {
+ // Clear the redo-stack and dispose
+ while (_redoStack.Count > 0)
+ {
+ _redoStack.Pop().Dispose();
+ }
+
+ _undoStack.Push(memento);
+ }
+ }
+ }
+
+ ///
+ /// This saves the elements of this surface to a stream.
+ /// Is used to save a template of the complete surface
+ ///
+ ///
+ ///
+ public long SaveElementsToStream(Stream streamWrite)
+ {
+ long bytesWritten = 0;
+ try
+ {
+ long lengtBefore = streamWrite.Length;
+ BinaryFormatter binaryWrite = new BinaryFormatter();
+ binaryWrite.Serialize(streamWrite, _elements);
+ bytesWritten = streamWrite.Length - lengtBefore;
+ }
+ catch (Exception e)
+ {
+ LOG.Error("Error serializing elements to stream.", e);
+ }
+
+ return bytesWritten;
+ }
+
+ ///
+ /// This loads elements from a stream, among others this is used to load a surface.
+ ///
+ ///
+ public void LoadElementsFromStream(Stream streamRead)
+ {
+ try
+ {
+ BinaryFormatter binaryRead = new BinaryFormatter();
+ IDrawableContainerList loadedElements = (IDrawableContainerList) binaryRead.Deserialize(streamRead);
+ loadedElements.Parent = this;
+ // Make sure the steplabels are sorted accoring to their number
+ _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number));
+ DeselectAllElements();
+ AddElements(loadedElements);
+ SelectElements(loadedElements);
+ FieldAggregator.BindElements(loadedElements);
+ }
+ catch (Exception e)
+ {
+ LOG.Error("Error serializing elements from stream.", e);
+ }
+ }
+
+ ///
+ /// This is called from the DrawingMode setter, which is not very correct...
+ /// But here an element is created which is not yet draw, thus "undrawnElement".
+ /// The element is than used while drawing on the surface.
+ ///
+ private void CreateUndrawnElement()
+ {
+ if (_undrawnElement != null)
+ {
+ FieldAggregator.UnbindElement(_undrawnElement);
+ }
+
+ switch (DrawingMode)
+ {
+ case DrawingModes.Rect:
+ _undrawnElement = new RectangleContainer(this);
+ break;
+ case DrawingModes.Ellipse:
+ _undrawnElement = new EllipseContainer(this);
+ break;
+ case DrawingModes.Text:
+ _undrawnElement = new TextContainer(this);
+ break;
+ case DrawingModes.SpeechBubble:
+ _undrawnElement = new SpeechbubbleContainer(this);
+ break;
+ case DrawingModes.StepLabel:
+ _undrawnElement = new StepLabelContainer(this);
+ break;
+ case DrawingModes.Line:
+ _undrawnElement = new LineContainer(this);
+ break;
+ case DrawingModes.Arrow:
+ _undrawnElement = new ArrowContainer(this);
+ break;
+ case DrawingModes.Highlight:
+ _undrawnElement = new HighlightContainer(this);
+ break;
+ case DrawingModes.Obfuscate:
+ _undrawnElement = new ObfuscateContainer(this);
+ break;
+ case DrawingModes.Crop:
+ _cropContainer = new CropContainer(this);
+ _undrawnElement = _cropContainer;
+ break;
+ case DrawingModes.Bitmap:
+ _undrawnElement = new ImageContainer(this);
+ break;
+ case DrawingModes.Path:
+ _undrawnElement = new FreehandContainer(this);
+ break;
+ case DrawingModes.None:
+ _undrawnElement = null;
+ break;
+ }
+
+ if (_undrawnElement != null)
+ {
+ FieldAggregator.BindElement(_undrawnElement);
+ }
+ }
+
+ #region Plugin interface implementations
+
+ public IImageContainer AddImageContainer(Image image, int x, int y)
+ {
+ ImageContainer bitmapContainer = new ImageContainer(this)
+ {
+ Image = image,
+ Left = x,
+ Top = y
+ };
+ AddElement(bitmapContainer);
+ return bitmapContainer;
+ }
+
+ public IImageContainer AddImageContainer(string filename, int x, int y)
+ {
+ ImageContainer bitmapContainer = new ImageContainer(this);
+ bitmapContainer.Load(filename);
+ bitmapContainer.Left = x;
+ bitmapContainer.Top = y;
+ AddElement(bitmapContainer);
+ return bitmapContainer;
+ }
+
+ public IIconContainer AddIconContainer(Icon icon, int x, int y)
+ {
+ IconContainer iconContainer = new IconContainer(this)
+ {
+ Icon = icon,
+ Left = x,
+ Top = y
+ };
+ AddElement(iconContainer);
+ return iconContainer;
+ }
+
+ public IIconContainer AddIconContainer(string filename, int x, int y)
+ {
+ IconContainer iconContainer = new IconContainer(this);
+ iconContainer.Load(filename);
+ iconContainer.Left = x;
+ iconContainer.Top = y;
+ AddElement(iconContainer);
+ return iconContainer;
+ }
+
+ public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y)
+ {
+ CursorContainer cursorContainer = new CursorContainer(this)
+ {
+ Cursor = cursor,
+ Left = x,
+ Top = y
+ };
+ AddElement(cursorContainer);
+ return cursorContainer;
+ }
+
+ public ICursorContainer AddCursorContainer(string filename, int x, int y)
+ {
+ CursorContainer cursorContainer = new CursorContainer(this);
+ cursorContainer.Load(filename);
+ cursorContainer.Left = x;
+ cursorContainer.Top = y;
+ AddElement(cursorContainer);
+ return cursorContainer;
+ }
+
+ 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,
+ Left = x,
+ Top = y
+ };
+ textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name);
+ textContainer.SetFieldValue(FieldType.FONT_BOLD, bold);
+ textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic);
+ textContainer.SetFieldValue(FieldType.FONT_SIZE, size);
+ textContainer.SetFieldValue(FieldType.FILL_COLOR, fillColor);
+ textContainer.SetFieldValue(FieldType.LINE_COLOR, color);
+ textContainer.SetFieldValue(FieldType.LINE_THICKNESS, borderSize);
+ textContainer.SetFieldValue(FieldType.SHADOW, shadow);
+ // Make sure the Text fits
+ textContainer.FitToText();
+
+ //AggregatedProperties.UpdateElement(textContainer);
+ AddElement(textContainer);
+ return textContainer;
+ }
+
+ #endregion
+
+ #region DragDrop
+
+ private void OnDragEnter(object sender, DragEventArgs e)
+ {
+ if (LOG.IsDebugEnabled)
+ {
+ LOG.Debug("DragEnter got following formats: ");
+ foreach (string format in ClipboardHelper.GetFormats(e.Data))
+ {
+ LOG.Debug(format);
+ }
+ }
+
+ if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy)
+ {
+ e.Effect = DragDropEffects.None;
+ }
+ else
+ {
+ if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits"))
+ {
+ e.Effect = DragDropEffects.Copy;
+ }
+ else
+ {
+ e.Effect = DragDropEffects.None;
+ }
+ }
+ }
+
+ ///
+ /// Handle the drag/drop
+ ///
+ ///
+ ///
+ private void OnDragDrop(object sender, DragEventArgs e)
+ {
+ Point mouse = PointToClient(new Point(e.X, e.Y));
+ if (e.Data.GetDataPresent("Text"))
+ {
+ string possibleUrl = ClipboardHelper.GetText(e.Data);
+ // Test if it's an url and try to download the image so we have it in the original form
+ if (possibleUrl != null && possibleUrl.StartsWith("http"))
+ {
+ using Image image = NetworkHelper.DownloadImage(possibleUrl);
+ if (image != null)
+ {
+ AddImageContainer(image, mouse.X, mouse.Y);
+ return;
+ }
+ }
+ }
+
+ foreach (Image image in ClipboardHelper.GetImages(e.Data))
+ {
+ AddImageContainer(image, mouse.X, mouse.Y);
+ mouse.Offset(10, 10);
+ image.Dispose();
+ }
+ }
+
+ #endregion
+
+ ///
+ /// Auto crop the image
+ ///
+ /// true if cropped
+ public bool AutoCrop()
+ {
+ Rectangle cropRectangle;
+ using (Image tmpImage = GetImageForExport())
+ {
+ cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference);
+ }
+
+ if (!IsCropPossible(ref cropRectangle))
+ {
+ return false;
+ }
+
+ DeselectAllElements();
+ // Maybe a bit obscure, but the following line creates a drop container
+ // It's available as "undrawnElement"
+ DrawingMode = DrawingModes.Crop;
+ _undrawnElement.Left = cropRectangle.X;
+ _undrawnElement.Top = cropRectangle.Y;
+ _undrawnElement.Width = cropRectangle.Width;
+ _undrawnElement.Height = cropRectangle.Height;
+ _undrawnElement.Status = EditStatus.UNDRAWN;
+ AddElement(_undrawnElement);
+ SelectElement(_undrawnElement);
+ _drawingElement = null;
+ _undrawnElement = null;
+ return true;
+ }
+
+ ///
+ /// A simple clear
+ ///
+ /// The color for the background
+ public void Clear(Color newColor)
+ {
+ //create a blank bitmap the same size as original
+ Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty);
+ if (newBitmap != null)
+ {
+ // Make undoable
+ MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false);
+ SetImage(newBitmap, false);
+ Invalidate();
+ }
+ }
+
+ ///
+ /// Apply a bitmap effect to the surface
+ ///
+ ///
+ public void ApplyBitmapEffect(IEffect effect)
+ {
+ BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait");
+ backgroundForm.Show();
+ Application.DoEvents();
+ try
+ {
+ Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
+ Matrix matrix = new Matrix();
+ Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix);
+ if (newImage != null)
+ {
+ // Make sure the elements move according to the offset the effect made the bitmap move
+ _elements.Transform(matrix);
+ // Make undoable
+ MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false);
+ SetImage(newImage, false);
+ Invalidate();
+ if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size)))
+ {
+ _surfaceSizeChanged(this, null);
+ }
+ }
+ else
+ {
+ // clean up matrix, as it hasn't been used in the undo stack.
+ matrix.Dispose();
+ }
+ }
+ finally
+ {
+ // Always close the background form
+ backgroundForm.CloseDialog();
+ }
+ }
+
+ ///
+ /// check if a crop is possible
+ ///
+ ///
+ /// true if this is possible
+ public bool IsCropPossible(ref Rectangle cropRectangle)
+ {
+ cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height);
+ if (cropRectangle.Left < 0)
+ {
+ cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height);
+ }
+
+ if (cropRectangle.Top < 0)
+ {
+ cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top);
+ }
+
+ if (cropRectangle.Left + cropRectangle.Width > Image.Width)
+ {
+ cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height);
+ }
+
+ if (cropRectangle.Top + cropRectangle.Height > Image.Height)
+ {
+ cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top);
+ }
+
+ if (cropRectangle.Height > 0 && cropRectangle.Width > 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area
+ ///
+ /// Who send
+ /// Type of message
+ /// Message itself
+ public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message)
+ {
+ if (_surfaceMessage != null)
+ {
+ var eventArgs = new SurfaceMessageEventArgs
+ {
+ Message = message,
+ MessageType = messageType,
+ Surface = this
+ };
+ _surfaceMessage(source, eventArgs);
+ }
+ }
+
+ ///
+ /// Crop the surface
+ ///
+ ///
+ ///
+ public bool ApplyCrop(Rectangle cropRectangle)
+ {
+ if (IsCropPossible(ref cropRectangle))
+ {
+ Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size);
+ Bitmap tmpImage;
+ // Make sure we have information, this this fails
+ try
+ {
+ 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;
+ }
+
+ return false;
+ }
+
+ ///
+ /// The background here is the captured image.
+ /// This is called from the SurfaceBackgroundChangeMemento.
+ ///
+ ///
+ ///
+ public void UndoBackgroundChange(Image previous, Matrix matrix)
+ {
+ SetImage(previous, false);
+ if (matrix != null)
+ {
+ _elements.Transform(matrix);
+ }
+
+ _surfaceSizeChanged?.Invoke(this, null);
+ Invalidate();
+ }
+
+ ///
+ /// Check if an adorner was "hit", and change the cursor if so
+ ///
+ /// MouseEventArgs
+ /// IAdorner
+ private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs)
+ {
+ foreach (IDrawableContainer drawableContainer in selectedElements)
+ {
+ foreach (IAdorner adorner in drawableContainer.Adorners)
+ {
+ if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location))
+ {
+ if (adorner.Cursor != null)
+ {
+ Cursor = adorner.Cursor;
+ }
+
+ return adorner;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Translate mouse coordinates as if they were applied directly to unscaled image.
+ ///
+ private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e)
+ => new MouseEventArgs(e.Button, e.Clicks, (int) (e.X / _zoomFactor), (int) (e.Y / _zoomFactor), e.Delta);
+
+ ///
+ /// This event handler is called when someone presses the mouse on a surface.
+ ///
+ ///
+ ///
+ private void SurfaceMouseDown(object sender, MouseEventArgs e)
+ {
+ e = InverseZoomMouseCoordinates(e);
+
+ // Handle Adorners
+ var adorner = FindActiveAdorner(e);
+ if (adorner != null)
+ {
+ adorner.MouseDown(sender, e);
+ return;
+ }
+
+ _mouseStart = e.Location;
+
+ // check contextmenu
+ if (e.Button == MouseButtons.Right)
+ {
+ IDrawableContainerList selectedList = null;
+ if (selectedElements != null && selectedElements.Count > 0)
+ {
+ selectedList = selectedElements;
+ }
+ else
+ {
+ // Single element
+ IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y);
+ if (rightClickedContainer != null)
+ {
+ selectedList = new DrawableContainerList(ID)
+ {
+ rightClickedContainer
+ };
+ }
+ }
+
+ if (selectedList != null && selectedList.Count > 0)
+ {
+ selectedList.ShowContextMenu(e, this);
+ }
+
+ return;
+ }
+
+ _mouseDown = true;
+ _isSurfaceMoveMadeUndoable = false;
+
+ if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop)))
+ {
+ RemoveElement(_cropContainer, false);
+ _cropContainer = null;
+ _drawingElement = null;
+ }
+
+ if (_drawingElement == null && DrawingMode != DrawingModes.None)
+ {
+ if (_undrawnElement == null)
+ {
+ DeselectAllElements();
+ if (_undrawnElement == null)
+ {
+ CreateUndrawnElement();
+ }
+ }
+
+ _drawingElement = _undrawnElement;
+ // if a new element has been drawn, set location and register it
+ if (_drawingElement != null)
+ {
+ if (_undrawnElement != null)
+ {
+ _drawingElement.Status = _undrawnElement.DefaultEditMode;
+ }
+
+ if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y))
+ {
+ _drawingElement.Left = _mouseStart.X;
+ _drawingElement.Top = _mouseStart.Y;
+ }
+
+ AddElement(_drawingElement);
+ _drawingElement.Selected = true;
+ }
+
+ _undrawnElement = null;
+ }
+ else
+ {
+ // check whether an existing element was clicked
+ // we save mouse down element separately from selectedElements (checked on mouse up),
+ // since it could be moved around before it is actually selected
+ _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y);
+
+ if (_mouseDownElement != null)
+ {
+ _mouseDownElement.Status = EditStatus.MOVING;
+ }
+ }
+ }
+
+ ///
+ /// This event handle is called when the mouse button is unpressed
+ ///
+ ///
+ ///
+ private void SurfaceMouseUp(object sender, MouseEventArgs e)
+ {
+ e = InverseZoomMouseCoordinates(e);
+
+ // Handle Adorners
+ var adorner = FindActiveAdorner(e);
+ if (adorner != null)
+ {
+ adorner.MouseUp(sender, e);
+ return;
+ }
+
+ Point currentMouse = new Point(e.X, e.Y);
+
+ _elements.Status = EditStatus.IDLE;
+ if (_mouseDownElement != null)
+ {
+ _mouseDownElement.Status = EditStatus.IDLE;
+ }
+
+ _mouseDown = false;
+ _mouseDownElement = null;
+ if (DrawingMode == DrawingModes.None)
+ {
+ // check whether an existing element was clicked
+ IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y);
+ bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift;
+ if (element != null)
+ {
+ element.Invalidate();
+ bool alreadySelected = selectedElements.Contains(element);
+ if (shiftModifier)
+ {
+ if (alreadySelected)
+ {
+ DeselectElement(element);
+ }
+ else
+ {
+ SelectElement(element);
+ }
+ }
+ else
+ {
+ if (!alreadySelected)
+ {
+ DeselectAllElements();
+ SelectElement(element);
+ }
+ }
+ }
+ else if (!shiftModifier)
+ {
+ DeselectAllElements();
+ }
+ }
+
+ if (selectedElements.Count > 0)
+ {
+ selectedElements.Invalidate();
+ selectedElements.Selected = true;
+ }
+
+ if (_drawingElement != null)
+ {
+ if (!_drawingElement.InitContent())
+ {
+ _elements.Remove(_drawingElement);
+ _drawingElement.Invalidate();
+ }
+ else
+ {
+ _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y);
+ _drawingElement.Invalidate();
+ if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5)
+ {
+ _drawingElement.Width = 25;
+ _drawingElement.Height = 25;
+ }
+
+ SelectElement(_drawingElement);
+ _drawingElement.Selected = true;
+ }
+
+ _drawingElement = null;
+ }
+ }
+
+ ///
+ /// This event handler is called when the mouse moves over the surface
+ ///
+ ///
+ ///
+ private void SurfaceMouseMove(object sender, MouseEventArgs e)
+ {
+ e = InverseZoomMouseCoordinates(e);
+
+ // Handle Adorners
+ var adorner = FindActiveAdorner(e);
+ if (adorner != null)
+ {
+ adorner.MouseMove(sender, e);
+ return;
+ }
+
+ Point currentMouse = e.Location;
+
+ Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default;
+
+ if (_mouseDown)
+ {
+ if (_mouseDownElement != null)
+ {
+ // an element is currently dragged
+ _mouseDownElement.Invalidate();
+ selectedElements.Invalidate();
+ // Move the element
+ if (_mouseDownElement.Selected)
+ {
+ if (!_isSurfaceMoveMadeUndoable)
+ {
+ // Only allow one undoable per mouse-down/move/up "cycle"
+ _isSurfaceMoveMadeUndoable = true;
+ selectedElements.MakeBoundsChangeUndoable(false);
+ }
+
+ // dragged element has been selected before -> move all
+ selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y);
+ }
+ else
+ {
+ if (!_isSurfaceMoveMadeUndoable)
+ {
+ // 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;
+ }
+ }
+ }
+
+ ///
+ /// This event handler is called when the surface is double clicked.
+ ///
+ ///
+ ///
+ private void SurfaceDoubleClick(object sender, MouseEventArgs e)
+ {
+ selectedElements.OnDoubleClick();
+ selectedElements.Invalidate();
+ }
+
+ ///
+ /// Privately used to get the rendered image with all the elements on it.
+ ///
+ ///
+ ///
+ private Image GetImage(RenderMode renderMode)
+ {
+ // Generate a copy of the original image with a dpi equal to the default...
+ Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare);
+ // otherwise we would have a problem drawing the image to the surface... :(
+ using (Graphics graphics = Graphics.FromImage(clone))
+ {
+ // Do not set the following, the containers need to decide themselves
+ //graphics.SmoothingMode = SmoothingMode.HighQuality;
+ //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ //graphics.CompositingQuality = CompositingQuality.HighQuality;
+ //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ _elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size));
+ }
+
+ return clone;
+ }
+
+ ///
+ /// This returns the image "result" of this surface, with all the elements rendered on it.
+ ///
+ ///
+ public Image GetImageForExport()
+ {
+ 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));
+
+ ///
+ /// This is the event handler for the Paint Event, try to draw as little as possible!
+ ///
+ ///
+ /// PaintEventArgs
+ private void SurfacePaint(object sender, PaintEventArgs paintEventArgs)
+ {
+ Graphics targetGraphics = paintEventArgs.Graphics;
+ Rectangle targetClipRectangle = paintEventArgs.ClipRectangle;
+ if (Rectangle.Empty.Equals(targetClipRectangle))
+ {
+ LOG.Debug("Empty cliprectangle??");
+ return;
+ }
+
+ // 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.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat)
+ {
+ _buffer.Dispose();
+ _buffer = null;
+ }
+ }
+
+ if (_buffer == null)
+ {
+ _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution);
+ LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height);
+ }
+
+ // Elements might need the bitmap, so we copy the part we need
+ using (Graphics graphics = Graphics.FromImage(_buffer))
+ {
+ // do not set the following, the containers need to decide this themselves!
+ //graphics.SmoothingMode = SmoothingMode.HighQuality;
+ //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ //graphics.CompositingQuality = CompositingQuality.HighQuality;
+ //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ DrawBackground(graphics, imageClipRectangle);
+ graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
+ graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2));
+ _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();
+ }
+ }
+ else
+ {
+ DrawBackground(targetGraphics, targetClipRectangle);
+ if (_zoomFactor == Fraction.Identity)
+ {
+ 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
+ targetGraphics.ResetClip();
+ // Draw adorners last
+ foreach (var drawableContainer in selectedElements)
+ {
+ foreach (var adorner in drawableContainer.Adorners)
+ {
+ adorner.Paint(paintEventArgs);
+ }
+ }
+ }
+
+ 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)
+ {
+ // check if we need to draw the checkerboard
+ if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null)
+ {
+ targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle);
+ }
+ else
+ {
+ targetGraphics.Clear(BackColor);
+ }
+ }
+
+ ///
+ /// Draw a checkboard when capturing with transparency
+ ///
+ /// PaintEventArgs
+ protected override void OnPaintBackground(PaintEventArgs e)
+ {
+ }
+
+ ///
+ /// Add a new element to the surface
+ ///
+ /// the new element
+ /// true if the adding should be undoable
+ /// true if invalidate needs to be called
+ public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true)
+ {
+ _elements.Add(element);
+ if (element is DrawableContainer container)
+ {
+ container.FieldChanged += Element_FieldChanged;
+ }
+
+ element.Parent = this;
+ if (element.Status == EditStatus.UNDRAWN)
+ {
+ element.Status = EditStatus.IDLE;
+ }
+
+ if (element.Selected)
+ {
+ // Use false, as the element is invalidated when invalidate == true anyway
+ SelectElement(element, false);
+ }
+
+ if (invalidate)
+ {
+ element.Invalidate();
+ }
+
+ if (makeUndoable)
+ {
+ MakeUndoable(new AddElementMemento(this, element), false);
+ }
+
+ _modified = true;
+ }
+
+ ///
+ /// Remove the list of elements
+ ///
+ /// IDrawableContainerList
+ /// flag specifying if the remove needs to be undoable
+ public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true)
+ {
+ // fix potential issues with iterating a changing list
+ DrawableContainerList cloned = new DrawableContainerList();
+ cloned.AddRange(elementsToRemove);
+ if (makeUndoable)
+ {
+ MakeUndoable(new DeleteElementsMemento(this, cloned), false);
+ }
+
+ SuspendLayout();
+ foreach (var drawableContainer in cloned)
+ {
+ RemoveElement(drawableContainer, false, false, false);
+ }
+
+ ResumeLayout();
+ Invalidate();
+ if (_movingElementChanged != null)
+ {
+ SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
+ {
+ Elements = cloned
+ };
+ _movingElementChanged(this, eventArgs);
+ }
+ }
+
+ ///
+ /// Remove an element of the elements list
+ ///
+ /// Element to remove
+ /// flag specifying if the remove needs to be undoable
+ /// flag specifying if an surface invalidate needs to be called
+ /// false to skip event generation
+ public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true)
+ {
+ DeselectElement(elementToRemove, generateEvents);
+ _elements.Remove(elementToRemove);
+ if (elementToRemove is DrawableContainer element)
+ {
+ element.FieldChanged -= Element_FieldChanged;
+ }
+
+ if (elementToRemove != null)
+ {
+ elementToRemove.Parent = null;
+ }
+
+ // Do not dispose, the memento should!! element.Dispose();
+ if (invalidate)
+ {
+ Invalidate();
+ }
+
+ if (makeUndoable)
+ {
+ MakeUndoable(new DeleteElementMemento(this, elementToRemove), false);
+ }
+
+ _modified = true;
+ }
+
+ ///
+ /// Add the supplied elements to the surface
+ ///
+ /// DrawableContainerList
+ /// true if the adding should be undoable
+ public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true)
+ {
+ // fix potential issues with iterating a changing list
+ DrawableContainerList cloned = new DrawableContainerList();
+ cloned.AddRange(elementsToAdd);
+ if (makeUndoable)
+ {
+ MakeUndoable(new AddElementsMemento(this, cloned), false);
+ }
+
+ SuspendLayout();
+ foreach (var element in cloned)
+ {
+ element.Selected = true;
+ AddElement(element, false, false);
+ }
+
+ ResumeLayout();
+ Invalidate();
+ }
+
+ ///
+ /// Returns if this surface has selected elements
+ ///
+ ///
+ public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0);
+
+ ///
+ /// Remove all the selected elements
+ ///
+ public void RemoveSelectedElements()
+ {
+ if (HasSelectedElements)
+ {
+ // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list.
+ RemoveElements(selectedElements);
+ if (_movingElementChanged != null)
+ {
+ SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs();
+ _movingElementChanged(this, eventArgs);
+ }
+ }
+ }
+
+ ///
+ /// Cut the selected elements from the surface to the clipboard
+ ///
+ public void CutSelectedElements()
+ {
+ if (HasSelectedElements)
+ {
+ ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
+ RemoveSelectedElements();
+ }
+ }
+
+ ///
+ /// Copy the selected elements to the clipboard
+ ///
+ public void CopySelectedElements()
+ {
+ if (HasSelectedElements)
+ {
+ ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
+ }
+ }
+
+ ///
+ /// This method is called to confirm/cancel "confirmable" elements, like the crop-container.
+ /// Called when pressing enter or using the "check" in the editor.
+ ///
+ ///
+ public void ConfirmSelectedConfirmableElements(bool confirm)
+ {
+ // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel)
+ List selectedDCs = new List(selectedElements);
+ foreach (IDrawableContainer dc in selectedDCs)
+ {
+ if (dc.Equals(_cropContainer))
+ {
+ DrawingMode = DrawingModes.None;
+ // No undo memento for the cropcontainer itself, only for the effect
+ RemoveElement(_cropContainer, false);
+ if (confirm)
+ {
+ ApplyCrop(_cropContainer.Bounds);
+ }
+
+ _cropContainer.Dispose();
+ _cropContainer = null;
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Paste all the elements that are on the clipboard
+ ///
+ public void PasteElementFromClipboard()
+ {
+ IDataObject clipboard = ClipboardHelper.GetDataObject();
+
+ var formats = ClipboardHelper.GetFormats(clipboard);
+ if (formats == null || formats.Count == 0)
+ {
+ return;
+ }
+
+ if (LOG.IsDebugEnabled)
+ {
+ LOG.Debug("List of clipboard formats available for pasting:");
+ foreach (string format in formats)
+ {
+ LOG.Debug("\tgot format: " + format);
+ }
+ }
+
+ if (formats.Contains(typeof(IDrawableContainerList).FullName))
+ {
+ IDrawableContainerList dcs = (IDrawableContainerList) ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList));
+ if (dcs != null)
+ {
+ // Make element(s) only move 10,10 if the surface is the same
+ bool isSameSurface = (dcs.ParentID == _uniqueId);
+ dcs.Parent = this;
+ var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty;
+ // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList
+ Rectangle drawableContainerListBounds = Rectangle.Empty;
+ foreach (var element in dcs)
+ {
+ drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty
+ ? element.DrawingBounds
+ : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds);
+ }
+
+ // And find a location inside the target surface to paste to
+ bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height;
+ if (!containersCanFit)
+ {
+ Point containersLocation = drawableContainerListBounds.Location;
+ containersLocation.Offset(moveOffset);
+ if (!Bounds.Contains(containersLocation))
+ {
+ // Easy fix for same surface
+ moveOffset = isSameSurface
+ ? new Point(-10, -10)
+ : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10);
+ }
+ }
+ else
+ {
+ Rectangle moveContainerListBounds = drawableContainerListBounds;
+ moveContainerListBounds.Offset(moveOffset);
+ // check if the element is inside
+ if (!Bounds.Contains(moveContainerListBounds))
+ {
+ // Easy fix for same surface
+ if (isSameSurface)
+ {
+ moveOffset = new Point(-10, -10);
+ }
+ else
+ {
+ // For different surface, which is most likely smaller
+ int offsetX = 0;
+ int offsetY = 0;
+ if (drawableContainerListBounds.Right > Bounds.Right)
+ {
+ offsetX = Bounds.Right - drawableContainerListBounds.Right;
+ // Correction for the correction
+ if (drawableContainerListBounds.Left + offsetX < 0)
+ {
+ offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX);
+ }
+ }
+
+ if (drawableContainerListBounds.Bottom > Bounds.Bottom)
+ {
+ offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom;
+ // Correction for the correction
+ if (drawableContainerListBounds.Top + offsetY < 0)
+ {
+ offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY);
+ }
+ }
+
+ moveOffset = new Point(offsetX, offsetY);
+ }
+ }
+ }
+
+ dcs.MoveBy(moveOffset.X, moveOffset.Y);
+ AddElements(dcs);
+ FieldAggregator.BindElements(dcs);
+ DeselectAllElements();
+ SelectElements(dcs);
+ }
+ }
+ else if (ClipboardHelper.ContainsImage(clipboard))
+ {
+ Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
+
+ foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard))
+ {
+ if (clipboardImage != null)
+ {
+ DeselectAllElements();
+ IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y);
+ SelectElement(container);
+ clipboardImage.Dispose();
+ pasteLocation.X += 10;
+ pasteLocation.Y += 10;
+ }
+ }
+ }
+ else if (ClipboardHelper.ContainsText(clipboard))
+ {
+ Point pasteLocation = GetPasteLocation(0.4f, 0.4f);
+
+ string text = ClipboardHelper.GetText(clipboard);
+ if (text != null)
+ {
+ DeselectAllElements();
+ ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y,
+ FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent);
+ SelectElement(textContainer);
+ }
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area.
+ /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area.
+ 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);
+ }
+
+ ///
+ /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space).
+ ///
+ 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
+ );
+ }
+
+ ///
+ /// Get the rectangle bounding all selected elements (in surface coordinates space),
+ /// or empty rectangle if nothing is selcted.
+ ///
+ public Rectangle GetSelectionRectangle()
+ => ToSurfaceCoordinates(selectedElements.DrawingBounds);
+
+ ///
+ /// Duplicate all the selecteded elements
+ ///
+ public void DuplicateSelectedElements()
+ {
+ LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count);
+ IDrawableContainerList dcs = selectedElements.Clone();
+ dcs.Parent = this;
+ dcs.MoveBy(10, 10);
+ AddElements(dcs);
+ DeselectAllElements();
+ SelectElements(dcs);
+ }
+
+ ///
+ /// Deselect the specified element
+ ///
+ /// IDrawableContainerList
+ /// false to skip event generation
+ public void DeselectElement(IDrawableContainer container, bool generateEvents = true)
+ {
+ container.Selected = false;
+ selectedElements.Remove(container);
+ FieldAggregator.UnbindElement(container);
+ if (generateEvents && _movingElementChanged != null)
+ {
+ var eventArgs = new SurfaceElementEventArgs
+ {
+ Elements = selectedElements
+ };
+ _movingElementChanged(this, eventArgs);
+ }
+ }
+
+ ///
+ /// Deselect the specified elements
+ ///
+ /// IDrawableContainerList
+ public void DeselectElements(IDrawableContainerList elements)
+ {
+ if (elements.Count == 0)
+ {
+ return;
+ }
+
+ while (elements.Count > 0)
+ {
+ var element = elements[0];
+ DeselectElement(element, false);
+ }
+
+ if (_movingElementChanged != null)
+ {
+ SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
+ {
+ Elements = selectedElements
+ };
+ _movingElementChanged(this, eventArgs);
+ }
+
+ Invalidate();
+ }
+
+ ///
+ /// Deselect all the selected elements
+ ///
+ public void DeselectAllElements()
+ {
+ DeselectElements(selectedElements);
+ }
+
+ ///
+ /// Select the supplied element
+ ///
+ ///
+ /// false to skip invalidation
+ /// false to skip event generation
+ public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true)
+ {
+ if (!selectedElements.Contains(container))
+ {
+ selectedElements.Add(container);
+ container.Selected = true;
+ FieldAggregator.BindElement(container);
+ if (generateEvents && _movingElementChanged != null)
+ {
+ SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
+ {
+ Elements = selectedElements
+ };
+ _movingElementChanged(this, eventArgs);
+ }
+
+ if (invalidate)
+ {
+ container.Invalidate();
+ }
+ }
+ }
+
+ ///
+ /// Select all elements, this is called when Ctrl+A is pressed
+ ///
+ public void SelectAllElements()
+ {
+ SelectElements(_elements);
+ }
+
+ ///
+ /// Select the supplied elements
+ ///
+ ///
+ public void SelectElements(IDrawableContainerList elements)
+ {
+ SuspendLayout();
+ foreach (var drawableContainer in elements)
+ {
+ var element = (DrawableContainer) drawableContainer;
+ SelectElement(element, false, false);
+ }
+
+ if (_movingElementChanged != null)
+ {
+ SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
+ {
+ Elements = selectedElements
+ };
+ _movingElementChanged(this, eventArgs);
+ }
+
+ ResumeLayout();
+ Invalidate();
+ }
+
+ ///
+ /// Process key presses on the surface, this is called from the editor (and NOT an override from the Control)
+ ///
+ /// Keys
+ /// false if no keys were processed
+ public bool ProcessCmdKey(Keys k)
+ {
+ if (selectedElements.Count > 0)
+ {
+ bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift;
+ int px = shiftModifier ? 10 : 1;
+ Point moveBy = Point.Empty;
+
+ switch (k)
+ {
+ case Keys.Left:
+ case Keys.Left | Keys.Shift:
+ moveBy = new Point(-px, 0);
+ break;
+ case Keys.Up:
+ case Keys.Up | Keys.Shift:
+ moveBy = new Point(0, -px);
+ break;
+ case Keys.Right:
+ case Keys.Right | Keys.Shift:
+ moveBy = new Point(px, 0);
+ break;
+ case Keys.Down:
+ case Keys.Down | Keys.Shift:
+ moveBy = new Point(0, px);
+ break;
+ case Keys.PageUp:
+ PullElementsUp();
+ break;
+ case Keys.PageDown:
+ PushElementsDown();
+ break;
+ case Keys.Home:
+ PullElementsToTop();
+ break;
+ case Keys.End:
+ PushElementsToBottom();
+ break;
+ case Keys.Enter:
+ ConfirmSelectedConfirmableElements(true);
+ break;
+ case Keys.Escape:
+ ConfirmSelectedConfirmableElements(false);
+ break;
+ /*case Keys.Delete:
+ RemoveSelectedElements();
+ break;*/
+ default:
+ return false;
+ }
+
+ if (!Point.Empty.Equals(moveBy))
+ {
+ selectedElements.MakeBoundsChangeUndoable(true);
+ selectedElements.MoveBy(moveBy.X, moveBy.Y);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Property for accessing the elements on the surface
+ ///
+ public IDrawableContainerList Elements => _elements;
+
+ ///
+ /// pulls selected elements up one level in hierarchy
+ ///
+ public void PullElementsUp()
+ {
+ _elements.PullElementsUp(selectedElements);
+ _elements.Invalidate();
+ }
+
+ ///
+ /// pushes selected elements up to top in hierarchy
+ ///
+ public void PullElementsToTop()
+ {
+ _elements.PullElementsToTop(selectedElements);
+ _elements.Invalidate();
+ }
+
+ ///
+ /// pushes selected elements down one level in hierarchy
+ ///
+ public void PushElementsDown()
+ {
+ _elements.PushElementsDown(selectedElements);
+ _elements.Invalidate();
+ }
+
+ ///
+ /// pushes selected elements down to bottom in hierarchy
+ ///
+ public void PushElementsToBottom()
+ {
+ _elements.PushElementsToBottom(selectedElements);
+ _elements.Invalidate();
+ }
+
+ ///
+ /// indicates whether the selected elements could be pulled up in hierarchy
+ ///
+ /// true if selected elements could be pulled up, false otherwise
+ public bool CanPullSelectionUp()
+ {
+ return _elements.CanPullUp(selectedElements);
+ }
+
+ ///
+ /// indicates whether the selected elements could be pushed down in hierarchy
+ ///
+ /// true if selected elements could be pushed down, false otherwise
+ public bool CanPushSelectionDown()
+ {
+ return _elements.CanPushDown(selectedElements);
+ }
+
+ public void Element_FieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ selectedElements.HandleFieldChangedEvent(sender, e);
+ }
+
+ public bool IsOnSurface(IDrawableContainer 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
+ );
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Drawing/TextContainer.cs b/src/Greenshot.Editor/Drawing/TextContainer.cs
similarity index 96%
rename from src/Greenshot/Drawing/TextContainer.cs
rename to src/Greenshot.Editor/Drawing/TextContainer.cs
index ccaae042c..4d670b4e0 100644
--- a/src/Greenshot/Drawing/TextContainer.cs
+++ b/src/Greenshot.Editor/Drawing/TextContainer.cs
@@ -1,691 +1,691 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Drawing.Fields;
-using Greenshot.Helpers;
-using Greenshot.Memento;
-using System;
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Text;
-using System.Runtime.Serialization;
-using System.Windows.Forms;
-using Greenshot.Base.Core;
-using Greenshot.Base.Interfaces.Drawing;
-
-namespace Greenshot.Drawing
-{
- ///
- /// Represents a textbox (extends RectangleContainer for border/background support
- ///
- [Serializable]
- public class TextContainer : RectangleContainer, ITextContainer
- {
- // If makeUndoable is true the next text-change will make the change undoable.
- // This is set to true AFTER the first change is made, as there is already a "add element" on the undo stack
- // Although the name is wrong, we can't change it due to file serialization
- // ReSharper disable once InconsistentNaming
- private bool makeUndoable;
- [NonSerialized] private Font _font;
- public Font Font => _font;
-
- [NonSerialized] private TextBox _textBox;
-
- ///
- /// The StringFormat object is not serializable!!
- ///
- [NonSerialized] private StringFormat _stringFormat = new StringFormat();
-
- public StringFormat StringFormat => _stringFormat;
-
- // Although the name is wrong, we can't change it due to file serialization
- // ReSharper disable once InconsistentNaming
- private string text;
-
- // there is a binding on the following property!
- public string Text
- {
- get => text;
- set => ChangeText(value, true);
- }
-
- internal void ChangeText(string newText, bool allowUndoable)
- {
- if ((text != null || newText == null) && string.Equals(text, newText)) return;
-
- if (makeUndoable && allowUndoable)
- {
- makeUndoable = false;
- _parent.MakeUndoable(new TextChangeMemento(this), false);
- }
-
- text = newText;
- OnPropertyChanged("Text");
- }
-
- public TextContainer(Surface parent) : base(parent)
- {
- Init();
- }
-
- protected override void InitializeFields()
- {
- AddField(GetType(), FieldType.LINE_THICKNESS, 2);
- AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
- AddField(GetType(), FieldType.SHADOW, true);
- AddField(GetType(), FieldType.FONT_ITALIC, false);
- AddField(GetType(), FieldType.FONT_BOLD, false);
- AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
- AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name);
- AddField(GetType(), FieldType.FONT_SIZE, 11f);
- AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center);
- AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center);
- }
-
- ///
- /// Do some logic to make sure all field are initiated correctly
- ///
- /// StreamingContext
- protected override void OnDeserialized(StreamingContext streamingContext)
- {
- base.OnDeserialized(streamingContext);
- Init();
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (_font != null)
- {
- _font.Dispose();
- _font = null;
- }
-
- if (_stringFormat != null)
- {
- _stringFormat.Dispose();
- _stringFormat = null;
- }
-
- if (_textBox != null)
- {
- _textBox.Dispose();
- _textBox = null;
- }
- }
-
- base.Dispose(disposing);
- }
-
- private void Init()
- {
- _stringFormat = new StringFormat
- {
- Trimming = StringTrimming.EllipsisWord
- };
-
- CreateTextBox();
-
- UpdateFormat();
- UpdateTextBoxFormat();
-
- PropertyChanged += TextContainer_PropertyChanged;
- FieldChanged += TextContainer_FieldChanged;
- }
-
- protected override void SwitchParent(Surface newParent)
- {
- if (_parent != null)
- {
- _parent.SizeChanged -= Parent_SizeChanged;
- }
-
- base.SwitchParent(newParent);
- if (_parent != null)
- {
- _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()
- {
- base.Invalidate();
- if (_textBox != null && _textBox.Visible)
- {
- _textBox.Invalidate();
- }
- }
-
- public void FitToText()
- {
- Size textSize = TextRenderer.MeasureText(text, _font);
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Width = textSize.Width + lineThickness;
- Height = textSize.Height + lineThickness;
- }
-
- private void TextContainer_PropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- if (_textBox == null)
- {
- return;
- }
-
- if (_textBox.Visible)
- {
- _textBox.Invalidate();
- }
-
- UpdateTextBoxPosition();
- UpdateTextBoxFormat();
- if (e.PropertyName.Equals("Selected"))
- {
- if (!Selected && _textBox.Visible)
- {
- HideTextBox();
- }
- else if (Selected && Status == EditStatus.DRAWING)
- {
- ShowTextBox();
- }
- else if (_parent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible)
- {
- // Fix (workaround) for BUG-1698
- _parent.KeysLocked = true;
- }
- }
-
- if (_textBox.Visible)
- {
- _textBox.Invalidate();
- }
- }
-
- private void TextContainer_FieldChanged(object sender, FieldChangedEventArgs e)
- {
- if (_textBox == null)
- {
- return;
- }
-
- if (_textBox.Visible)
- {
- _textBox.Invalidate();
- }
-
- // Only dispose the font, and re-create it, when a font field has changed.
- if (e.Field.FieldType.Name.StartsWith("FONT"))
- {
- if (_font != null)
- {
- _font.Dispose();
- _font = null;
- }
-
- UpdateFormat();
- }
- else
- {
- UpdateAlignment();
- }
-
- UpdateTextBoxFormat();
-
- if (_textBox.Visible)
- {
- _textBox.Invalidate();
- }
- }
-
- public override void OnDoubleClick()
- {
- ShowTextBox();
- }
-
- private void CreateTextBox()
- {
- _textBox = new TextBox
- {
- ImeMode = ImeMode.On,
- Multiline = true,
- AcceptsTab = true,
- AcceptsReturn = true,
- BorderStyle = BorderStyle.None,
- Visible = false,
- Font = new Font(FontFamily.GenericSansSerif, 1) // just need something non-default here
- };
-
- _textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged);
- _textBox.LostFocus += textBox_LostFocus;
- _textBox.KeyDown += textBox_KeyDown;
- }
-
- private void ShowTextBox()
- {
- if (_parent != null)
- {
- _parent.KeysLocked = true;
- _parent.Controls.Add(_textBox);
- }
-
- EnsureTextBoxContrast();
- if (_textBox != null)
- {
- _textBox.Show();
- _textBox.Focus();
- }
- }
-
- ///
- /// Makes textbox background dark if text color is very bright
- ///
- private void EnsureTextBoxContrast()
- {
- if (_textBox == null)
- {
- return;
- }
-
- Color lc = GetFieldValueAsColor(FieldType.LINE_COLOR);
- if (lc.R > 203 && lc.G > 203 && lc.B > 203)
- {
- _textBox.BackColor = Color.FromArgb(51, 51, 51);
- }
- else
- {
- _textBox.BackColor = Color.White;
- }
- }
-
- private void HideTextBox()
- {
- _parent?.Focus();
- _textBox?.Hide();
- if (_parent == null)
- {
- return;
- }
-
- _parent.KeysLocked = false;
- _parent.Controls.Remove(_textBox);
- }
-
- ///
- /// Make sure the size of the font is scaled
- ///
- ///
- public override void Transform(Matrix matrix)
- {
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- int pixelsBefore = rect.Width * rect.Height;
-
- // Transform this container
- base.Transform(matrix);
- rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
-
- int pixelsAfter = rect.Width * rect.Height;
- float factor = pixelsAfter / (float) pixelsBefore;
-
- float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE);
- fontSize *= factor;
- SetFieldValue(FieldType.FONT_SIZE, fontSize);
- UpdateFormat();
- }
-
- private Font CreateFont(string fontFamilyName, bool fontBold, bool fontItalic, float fontSize)
- {
- FontStyle fontStyle = FontStyle.Regular;
-
- bool hasStyle = false;
- using var fontFamily = new FontFamily(fontFamilyName);
- bool boldAvailable = fontFamily.IsStyleAvailable(FontStyle.Bold);
- if (fontBold && boldAvailable)
- {
- fontStyle |= FontStyle.Bold;
- hasStyle = true;
- }
-
- bool italicAvailable = fontFamily.IsStyleAvailable(FontStyle.Italic);
- if (fontItalic && italicAvailable)
- {
- fontStyle |= FontStyle.Italic;
- hasStyle = true;
- }
-
- if (!hasStyle)
- {
- bool regularAvailable = fontFamily.IsStyleAvailable(FontStyle.Regular);
- if (regularAvailable)
- {
- fontStyle = FontStyle.Regular;
- }
- else
- {
- if (boldAvailable)
- {
- fontStyle = FontStyle.Bold;
- }
- else if (italicAvailable)
- {
- fontStyle = FontStyle.Italic;
- }
- }
- }
-
- return new Font(fontFamily, fontSize, fontStyle, GraphicsUnit.Pixel);
- }
-
- ///
- /// Generate the Font-Formal so we can draw correctly
- ///
- protected void UpdateFormat()
- {
- if (_textBox == null)
- {
- return;
- }
-
- string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY);
- bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD);
- bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC);
- float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE);
- try
- {
- var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
- _font?.Dispose();
- _font = newFont;
- }
- catch (Exception ex)
- {
- // Problem, try again with the default
- try
- {
- fontFamily = FontFamily.GenericSansSerif.Name;
- SetFieldValue(FieldType.FONT_FAMILY, fontFamily);
- var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
- _font?.Dispose();
- _font = newFont;
- }
- catch (Exception)
- {
- // When this happens... the PC is broken
- ex.Data.Add("fontFamilyName", fontFamily);
- ex.Data.Add("fontBold", fontBold);
- ex.Data.Add("fontItalic", fontItalic);
- ex.Data.Add("fontSize", fontSize);
- throw ex;
- }
- }
-
- UpdateTextBoxFont();
-
- UpdateAlignment();
- }
-
- private void UpdateAlignment()
- {
- _stringFormat.Alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT);
- _stringFormat.LineAlignment = (StringAlignment) GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT);
- }
-
- ///
- /// Set TextBox font according to the TextContainer font and the parent zoom factor.
- ///
- 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;
- }
-
- ///
- /// 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...
- ///
- private void UpdateTextBoxPosition()
- {
- if (_textBox == null || Parent == null)
- {
- return;
- }
-
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
-
- int lineWidth = (int) Math.Floor(lineThickness / 2d);
- int correction = (lineThickness + 1) % 2;
- if (lineThickness <= 1)
- {
- lineWidth = 1;
- correction = -1;
- }
-
- Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle);
- _textBox.Left = displayRectangle.X + lineWidth;
- _textBox.Top = displayRectangle.Y + lineWidth;
- if (lineThickness <= 1)
- {
- lineWidth = 0;
- }
-
- _textBox.Width = displayRectangle.Width - 2 * lineWidth + correction;
- _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction;
- }
-
- ///
- /// Set TextBox text align and fore color according to field values.
- ///
- private void UpdateTextBoxFormat()
- {
- if (_textBox == null)
- {
- return;
- }
-
- var alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT);
- switch (alignment)
- {
- case StringAlignment.Near:
- _textBox.TextAlign = HorizontalAlignment.Left;
- break;
- case StringAlignment.Far:
- _textBox.TextAlign = HorizontalAlignment.Right;
- break;
- case StringAlignment.Center:
- _textBox.TextAlign = HorizontalAlignment.Center;
- break;
- }
-
- var lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- _textBox.ForeColor = lineColor;
- }
-
- private void textBox_KeyDown(object sender, KeyEventArgs e)
- {
- // ESC and Enter/Return (w/o Shift) hide text editor
- if (e.KeyCode == Keys.Escape || ((e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) && e.Modifiers == Keys.None))
- {
- HideTextBox();
- e.SuppressKeyPress = true;
- }
-
- if (e.Control && !e.Alt && e.KeyCode == Keys.A)
- {
- _textBox.SelectAll();
- }
-
- // Added for FEATURE-1064
- if (e.KeyCode == Keys.Back && e.Control)
- {
- e.SuppressKeyPress = true;
- int selStart = _textBox.SelectionStart;
- while (selStart > 0 && _textBox.Text.Substring(selStart - 1, 1) == " ")
- {
- selStart--;
- }
-
- int prevSpacePos = -1;
- if (selStart != 0)
- {
- prevSpacePos = _textBox.Text.LastIndexOf(' ', selStart - 1);
- }
-
- _textBox.Select(prevSpacePos + 1, _textBox.SelectionStart - prevSpacePos - 1);
- _textBox.SelectedText = string.Empty;
- }
- }
-
- private void textBox_LostFocus(object sender, EventArgs e)
- {
- // next change will be made undoable
- makeUndoable = true;
- HideTextBox();
- }
-
- public override void Draw(Graphics graphics, RenderMode rm)
- {
- base.Draw(graphics, rm);
-
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.None;
- graphics.TextRenderingHint = TextRenderingHint.SystemDefault;
-
- Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- if (Selected && rm == RenderMode.EDIT)
- {
- DrawSelectionBorder(graphics, rect);
- }
-
- if (string.IsNullOrEmpty(text))
- {
- return;
- }
-
- // we only draw the shadow if there is no background
- bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
- Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
- int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
- Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
- bool drawShadow = shadow && (fillColor == Color.Transparent || fillColor == Color.Empty);
-
- DrawText(graphics, rect, lineThickness, lineColor, drawShadow, _stringFormat, text, _font);
- }
-
- ///
- /// This method can be used from other containers
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text,
- Font font)
- {
-#if DEBUG
- Debug.Assert(font != null);
-#else
- if (font == null)
- {
- return;
- }
-#endif
- int textOffset = lineThickness > 0 ? (int) Math.Ceiling(lineThickness / 2d) : 0;
- // draw shadow before anything else
- if (drawShadow)
- {
- int basealpha = 100;
- int alpha = basealpha;
- int steps = 5;
- int currentStep = 1;
- while (currentStep <= steps)
- {
- int offset = currentStep;
- Rectangle shadowRect = GuiRectangle.GetGuiRectangle(drawingRectange.Left + offset, drawingRectange.Top + offset, drawingRectange.Width, drawingRectange.Height);
- if (lineThickness > 0)
- {
- shadowRect.Inflate(-textOffset, -textOffset);
- }
- using Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100));
- graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat);
-
- currentStep++;
- alpha -= basealpha / steps;
- }
- }
-
- if (lineThickness > 0)
- {
- drawingRectange.Inflate(-textOffset, -textOffset);
- }
- using (Brush fontBrush = new SolidBrush(fontColor))
- {
- if (stringFormat != null)
- {
- graphics.DrawString(text, font, fontBrush, drawingRectange, stringFormat);
- }
- else
- {
- graphics.DrawString(text, font, fontBrush, drawingRectange);
- }
- }
- }
-
- public override bool ClickableAt(int x, int y)
- {
- Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
- r.Inflate(5, 5);
- return r.Contains(x, y);
- }
- }
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Text;
+using System.Runtime.Serialization;
+using System.Windows.Forms;
+using Greenshot.Base.Core;
+using Greenshot.Base.Interfaces.Drawing;
+using Greenshot.Editor.Drawing.Fields;
+using Greenshot.Editor.Helpers;
+using Greenshot.Editor.Memento;
+
+namespace Greenshot.Editor.Drawing
+{
+ ///
+ /// Represents a textbox (extends RectangleContainer for border/background support
+ ///
+ [Serializable]
+ public class TextContainer : RectangleContainer, ITextContainer
+ {
+ // If makeUndoable is true the next text-change will make the change undoable.
+ // This is set to true AFTER the first change is made, as there is already a "add element" on the undo stack
+ // Although the name is wrong, we can't change it due to file serialization
+ // ReSharper disable once InconsistentNaming
+ private bool makeUndoable;
+ [NonSerialized] private Font _font;
+ public Font Font => _font;
+
+ [NonSerialized] private TextBox _textBox;
+
+ ///
+ /// The StringFormat object is not serializable!!
+ ///
+ [NonSerialized] private StringFormat _stringFormat = new StringFormat();
+
+ public StringFormat StringFormat => _stringFormat;
+
+ // Although the name is wrong, we can't change it due to file serialization
+ // ReSharper disable once InconsistentNaming
+ private string text;
+
+ // there is a binding on the following property!
+ public string Text
+ {
+ get => text;
+ set => ChangeText(value, true);
+ }
+
+ internal void ChangeText(string newText, bool allowUndoable)
+ {
+ if ((text != null || newText == null) && string.Equals(text, newText)) return;
+
+ if (makeUndoable && allowUndoable)
+ {
+ makeUndoable = false;
+ _parent.MakeUndoable(new TextChangeMemento(this), false);
+ }
+
+ text = newText;
+ OnPropertyChanged("Text");
+ }
+
+ public TextContainer(Surface parent) : base(parent)
+ {
+ Init();
+ }
+
+ protected override void InitializeFields()
+ {
+ AddField(GetType(), FieldType.LINE_THICKNESS, 2);
+ AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
+ AddField(GetType(), FieldType.SHADOW, true);
+ AddField(GetType(), FieldType.FONT_ITALIC, false);
+ AddField(GetType(), FieldType.FONT_BOLD, false);
+ AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent);
+ AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name);
+ AddField(GetType(), FieldType.FONT_SIZE, 11f);
+ AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center);
+ AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center);
+ }
+
+ ///
+ /// Do some logic to make sure all field are initiated correctly
+ ///
+ /// StreamingContext
+ protected override void OnDeserialized(StreamingContext streamingContext)
+ {
+ base.OnDeserialized(streamingContext);
+ Init();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_font != null)
+ {
+ _font.Dispose();
+ _font = null;
+ }
+
+ if (_stringFormat != null)
+ {
+ _stringFormat.Dispose();
+ _stringFormat = null;
+ }
+
+ if (_textBox != null)
+ {
+ _textBox.Dispose();
+ _textBox = null;
+ }
+ }
+
+ base.Dispose(disposing);
+ }
+
+ private void Init()
+ {
+ _stringFormat = new StringFormat
+ {
+ Trimming = StringTrimming.EllipsisWord
+ };
+
+ CreateTextBox();
+
+ UpdateFormat();
+ UpdateTextBoxFormat();
+
+ PropertyChanged += TextContainer_PropertyChanged;
+ FieldChanged += TextContainer_FieldChanged;
+ }
+
+ protected override void SwitchParent(Surface newParent)
+ {
+ if (_parent != null)
+ {
+ _parent.SizeChanged -= Parent_SizeChanged;
+ }
+
+ base.SwitchParent(newParent);
+ if (_parent != null)
+ {
+ _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()
+ {
+ base.Invalidate();
+ if (_textBox != null && _textBox.Visible)
+ {
+ _textBox.Invalidate();
+ }
+ }
+
+ public void FitToText()
+ {
+ Size textSize = TextRenderer.MeasureText(text, _font);
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Width = textSize.Width + lineThickness;
+ Height = textSize.Height + lineThickness;
+ }
+
+ private void TextContainer_PropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (_textBox == null)
+ {
+ return;
+ }
+
+ if (_textBox.Visible)
+ {
+ _textBox.Invalidate();
+ }
+
+ UpdateTextBoxPosition();
+ UpdateTextBoxFormat();
+ if (e.PropertyName.Equals("Selected"))
+ {
+ if (!Selected && _textBox.Visible)
+ {
+ HideTextBox();
+ }
+ else if (Selected && Status == EditStatus.DRAWING)
+ {
+ ShowTextBox();
+ }
+ else if (_parent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible)
+ {
+ // Fix (workaround) for BUG-1698
+ _parent.KeysLocked = true;
+ }
+ }
+
+ if (_textBox.Visible)
+ {
+ _textBox.Invalidate();
+ }
+ }
+
+ private void TextContainer_FieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ if (_textBox == null)
+ {
+ return;
+ }
+
+ if (_textBox.Visible)
+ {
+ _textBox.Invalidate();
+ }
+
+ // Only dispose the font, and re-create it, when a font field has changed.
+ if (e.Field.FieldType.Name.StartsWith("FONT"))
+ {
+ if (_font != null)
+ {
+ _font.Dispose();
+ _font = null;
+ }
+
+ UpdateFormat();
+ }
+ else
+ {
+ UpdateAlignment();
+ }
+
+ UpdateTextBoxFormat();
+
+ if (_textBox.Visible)
+ {
+ _textBox.Invalidate();
+ }
+ }
+
+ public override void OnDoubleClick()
+ {
+ ShowTextBox();
+ }
+
+ private void CreateTextBox()
+ {
+ _textBox = new TextBox
+ {
+ ImeMode = ImeMode.On,
+ Multiline = true,
+ AcceptsTab = true,
+ AcceptsReturn = true,
+ BorderStyle = BorderStyle.None,
+ Visible = false,
+ Font = new Font(FontFamily.GenericSansSerif, 1) // just need something non-default here
+ };
+
+ _textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged);
+ _textBox.LostFocus += textBox_LostFocus;
+ _textBox.KeyDown += textBox_KeyDown;
+ }
+
+ private void ShowTextBox()
+ {
+ if (_parent != null)
+ {
+ _parent.KeysLocked = true;
+ _parent.Controls.Add(_textBox);
+ }
+
+ EnsureTextBoxContrast();
+ if (_textBox != null)
+ {
+ _textBox.Show();
+ _textBox.Focus();
+ }
+ }
+
+ ///
+ /// Makes textbox background dark if text color is very bright
+ ///
+ private void EnsureTextBoxContrast()
+ {
+ if (_textBox == null)
+ {
+ return;
+ }
+
+ Color lc = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ if (lc.R > 203 && lc.G > 203 && lc.B > 203)
+ {
+ _textBox.BackColor = Color.FromArgb(51, 51, 51);
+ }
+ else
+ {
+ _textBox.BackColor = Color.White;
+ }
+ }
+
+ private void HideTextBox()
+ {
+ _parent?.Focus();
+ _textBox?.Hide();
+ if (_parent == null)
+ {
+ return;
+ }
+
+ _parent.KeysLocked = false;
+ _parent.Controls.Remove(_textBox);
+ }
+
+ ///
+ /// Make sure the size of the font is scaled
+ ///
+ ///
+ public override void Transform(Matrix matrix)
+ {
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ int pixelsBefore = rect.Width * rect.Height;
+
+ // Transform this container
+ base.Transform(matrix);
+ rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+
+ int pixelsAfter = rect.Width * rect.Height;
+ float factor = pixelsAfter / (float) pixelsBefore;
+
+ float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE);
+ fontSize *= factor;
+ SetFieldValue(FieldType.FONT_SIZE, fontSize);
+ UpdateFormat();
+ }
+
+ private Font CreateFont(string fontFamilyName, bool fontBold, bool fontItalic, float fontSize)
+ {
+ FontStyle fontStyle = FontStyle.Regular;
+
+ bool hasStyle = false;
+ using var fontFamily = new FontFamily(fontFamilyName);
+ bool boldAvailable = fontFamily.IsStyleAvailable(FontStyle.Bold);
+ if (fontBold && boldAvailable)
+ {
+ fontStyle |= FontStyle.Bold;
+ hasStyle = true;
+ }
+
+ bool italicAvailable = fontFamily.IsStyleAvailable(FontStyle.Italic);
+ if (fontItalic && italicAvailable)
+ {
+ fontStyle |= FontStyle.Italic;
+ hasStyle = true;
+ }
+
+ if (!hasStyle)
+ {
+ bool regularAvailable = fontFamily.IsStyleAvailable(FontStyle.Regular);
+ if (regularAvailable)
+ {
+ fontStyle = FontStyle.Regular;
+ }
+ else
+ {
+ if (boldAvailable)
+ {
+ fontStyle = FontStyle.Bold;
+ }
+ else if (italicAvailable)
+ {
+ fontStyle = FontStyle.Italic;
+ }
+ }
+ }
+
+ return new Font(fontFamily, fontSize, fontStyle, GraphicsUnit.Pixel);
+ }
+
+ ///
+ /// Generate the Font-Formal so we can draw correctly
+ ///
+ protected void UpdateFormat()
+ {
+ if (_textBox == null)
+ {
+ return;
+ }
+
+ string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY);
+ bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD);
+ bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC);
+ float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE);
+ try
+ {
+ var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
+ _font?.Dispose();
+ _font = newFont;
+ }
+ catch (Exception ex)
+ {
+ // Problem, try again with the default
+ try
+ {
+ fontFamily = FontFamily.GenericSansSerif.Name;
+ SetFieldValue(FieldType.FONT_FAMILY, fontFamily);
+ var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
+ _font?.Dispose();
+ _font = newFont;
+ }
+ catch (Exception)
+ {
+ // When this happens... the PC is broken
+ ex.Data.Add("fontFamilyName", fontFamily);
+ ex.Data.Add("fontBold", fontBold);
+ ex.Data.Add("fontItalic", fontItalic);
+ ex.Data.Add("fontSize", fontSize);
+ throw ex;
+ }
+ }
+
+ UpdateTextBoxFont();
+
+ UpdateAlignment();
+ }
+
+ private void UpdateAlignment()
+ {
+ _stringFormat.Alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT);
+ _stringFormat.LineAlignment = (StringAlignment) GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT);
+ }
+
+ ///
+ /// Set TextBox font according to the TextContainer font and the parent zoom factor.
+ ///
+ 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;
+ }
+
+ ///
+ /// 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...
+ ///
+ private void UpdateTextBoxPosition()
+ {
+ if (_textBox == null || Parent == null)
+ {
+ return;
+ }
+
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+
+ int lineWidth = (int) Math.Floor(lineThickness / 2d);
+ int correction = (lineThickness + 1) % 2;
+ if (lineThickness <= 1)
+ {
+ lineWidth = 1;
+ correction = -1;
+ }
+
+ Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle);
+ _textBox.Left = displayRectangle.X + lineWidth;
+ _textBox.Top = displayRectangle.Y + lineWidth;
+ if (lineThickness <= 1)
+ {
+ lineWidth = 0;
+ }
+
+ _textBox.Width = displayRectangle.Width - 2 * lineWidth + correction;
+ _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction;
+ }
+
+ ///
+ /// Set TextBox text align and fore color according to field values.
+ ///
+ private void UpdateTextBoxFormat()
+ {
+ if (_textBox == null)
+ {
+ return;
+ }
+
+ var alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT);
+ switch (alignment)
+ {
+ case StringAlignment.Near:
+ _textBox.TextAlign = HorizontalAlignment.Left;
+ break;
+ case StringAlignment.Far:
+ _textBox.TextAlign = HorizontalAlignment.Right;
+ break;
+ case StringAlignment.Center:
+ _textBox.TextAlign = HorizontalAlignment.Center;
+ break;
+ }
+
+ var lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ _textBox.ForeColor = lineColor;
+ }
+
+ private void textBox_KeyDown(object sender, KeyEventArgs e)
+ {
+ // ESC and Enter/Return (w/o Shift) hide text editor
+ if (e.KeyCode == Keys.Escape || ((e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) && e.Modifiers == Keys.None))
+ {
+ HideTextBox();
+ e.SuppressKeyPress = true;
+ }
+
+ if (e.Control && !e.Alt && e.KeyCode == Keys.A)
+ {
+ _textBox.SelectAll();
+ }
+
+ // Added for FEATURE-1064
+ if (e.KeyCode == Keys.Back && e.Control)
+ {
+ e.SuppressKeyPress = true;
+ int selStart = _textBox.SelectionStart;
+ while (selStart > 0 && _textBox.Text.Substring(selStart - 1, 1) == " ")
+ {
+ selStart--;
+ }
+
+ int prevSpacePos = -1;
+ if (selStart != 0)
+ {
+ prevSpacePos = _textBox.Text.LastIndexOf(' ', selStart - 1);
+ }
+
+ _textBox.Select(prevSpacePos + 1, _textBox.SelectionStart - prevSpacePos - 1);
+ _textBox.SelectedText = string.Empty;
+ }
+ }
+
+ private void textBox_LostFocus(object sender, EventArgs e)
+ {
+ // next change will be made undoable
+ makeUndoable = true;
+ HideTextBox();
+ }
+
+ public override void Draw(Graphics graphics, RenderMode rm)
+ {
+ base.Draw(graphics, rm);
+
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.None;
+ graphics.TextRenderingHint = TextRenderingHint.SystemDefault;
+
+ Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ if (Selected && rm == RenderMode.EDIT)
+ {
+ DrawSelectionBorder(graphics, rect);
+ }
+
+ if (string.IsNullOrEmpty(text))
+ {
+ return;
+ }
+
+ // we only draw the shadow if there is no background
+ bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
+ Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR);
+ int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
+ Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
+ bool drawShadow = shadow && (fillColor == Color.Transparent || fillColor == Color.Empty);
+
+ DrawText(graphics, rect, lineThickness, lineColor, drawShadow, _stringFormat, text, _font);
+ }
+
+ ///
+ /// This method can be used from other containers
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text,
+ Font font)
+ {
+#if DEBUG
+ Debug.Assert(font != null);
+#else
+ if (font == null)
+ {
+ return;
+ }
+#endif
+ int textOffset = lineThickness > 0 ? (int) Math.Ceiling(lineThickness / 2d) : 0;
+ // draw shadow before anything else
+ if (drawShadow)
+ {
+ int basealpha = 100;
+ int alpha = basealpha;
+ int steps = 5;
+ int currentStep = 1;
+ while (currentStep <= steps)
+ {
+ int offset = currentStep;
+ Rectangle shadowRect = GuiRectangle.GetGuiRectangle(drawingRectange.Left + offset, drawingRectange.Top + offset, drawingRectange.Width, drawingRectange.Height);
+ if (lineThickness > 0)
+ {
+ shadowRect.Inflate(-textOffset, -textOffset);
+ }
+ using Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100));
+ graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat);
+
+ currentStep++;
+ alpha -= basealpha / steps;
+ }
+ }
+
+ if (lineThickness > 0)
+ {
+ drawingRectange.Inflate(-textOffset, -textOffset);
+ }
+ using (Brush fontBrush = new SolidBrush(fontColor))
+ {
+ if (stringFormat != null)
+ {
+ graphics.DrawString(text, font, fontBrush, drawingRectange, stringFormat);
+ }
+ else
+ {
+ graphics.DrawString(text, font, fontBrush, drawingRectange);
+ }
+ }
+ }
+
+ public override bool ClickableAt(int x, int y)
+ {
+ Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
+ r.Inflate(5, 5);
+ return r.Contains(x, y);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Greenshot/Forms/ColorDialog.Designer.cs b/src/Greenshot.Editor/Forms/ColorDialog.Designer.cs
similarity index 95%
rename from src/Greenshot/Forms/ColorDialog.Designer.cs
rename to src/Greenshot.Editor/Forms/ColorDialog.Designer.cs
index c2a35728c..0f9426a67 100644
--- a/src/Greenshot/Forms/ColorDialog.Designer.cs
+++ b/src/Greenshot.Editor/Forms/ColorDialog.Designer.cs
@@ -1,287 +1,288 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Greenshot.Base.Controls;
-
-namespace Greenshot.Forms {
- public partial class ColorDialog {
- ///
- /// Designer variable used to keep track of non-visual components.
- ///
- private System.ComponentModel.IContainer components = null;
-
- ///
- /// Disposes resources used by the form.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
- {
- if (disposing) {
- if (components != null) {
- components.Dispose();
- }
- }
- base.Dispose(disposing);
- }
-
- ///
- /// This method is required for Windows Forms designer support.
- /// Do not change the method contents inside the source code editor. The Forms designer might
- /// not be able to load this method if it was changed manually.
- ///
- private void InitializeComponent()
- {
- System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ColorDialog));
- this.btnTransparent = new GreenshotButton();
- this.colorPanel = new System.Windows.Forms.Panel();
- this.labelHtmlColor = new GreenshotLabel();
- this.textBoxHtmlColor = new System.Windows.Forms.TextBox();
- this.labelRed = new GreenshotLabel();
- this.labelGreen = new GreenshotLabel();
- this.labelBlue = new GreenshotLabel();
- this.textBoxRed = new System.Windows.Forms.TextBox();
- this.textBoxGreen = new System.Windows.Forms.TextBox();
- this.textBoxBlue = new System.Windows.Forms.TextBox();
- this.labelRecentColors = new GreenshotLabel();
- this.textBoxAlpha = new System.Windows.Forms.TextBox();
- this.labelAlpha = new GreenshotLabel();
- this.btnApply = new GreenshotButton();
- this.pipette = new Greenshot.Controls.Pipette();
- this.SuspendLayout();
- //
- // btnTransparent
- //
- this.btnTransparent.BackColor = System.Drawing.Color.Transparent;
- this.btnTransparent.LanguageKey = "colorpicker_transparent";
- this.btnTransparent.Location = new System.Drawing.Point(210, 4);
- this.btnTransparent.Name = "btnTransparent";
- this.btnTransparent.Size = new System.Drawing.Size(78, 23);
- this.btnTransparent.TabIndex = 0;
- this.btnTransparent.TabStop = false;
- this.btnTransparent.Text = "Transparent";
- this.btnTransparent.UseVisualStyleBackColor = false;
- this.btnTransparent.Click += new System.EventHandler(this.BtnTransparentClick);
- //
- // colorPanel
- //
- this.colorPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
- this.colorPanel.Location = new System.Drawing.Point(213, 30);
- this.colorPanel.Name = "colorPanel";
- this.colorPanel.Size = new System.Drawing.Size(33, 23);
- this.colorPanel.TabIndex = 1;
- //
- // labelHtmlColor
- //
- this.labelHtmlColor.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
- this.labelHtmlColor.LanguageKey = "colorpicker_htmlcolor";
- this.labelHtmlColor.Location = new System.Drawing.Point(210, 57);
- this.labelHtmlColor.Name = "labelHtmlColor";
- this.labelHtmlColor.Size = new System.Drawing.Size(78, 17);
- this.labelHtmlColor.TabIndex = 2;
- this.labelHtmlColor.Text = "HTML color";
- //
- // textBoxHtmlColor
- //
- this.textBoxHtmlColor.Location = new System.Drawing.Point(210, 71);
- this.textBoxHtmlColor.Name = "textBoxHtmlColor";
- this.textBoxHtmlColor.Size = new System.Drawing.Size(78, 20);
- this.textBoxHtmlColor.TabIndex = 1;
- this.textBoxHtmlColor.Click += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxHtmlColor.TextChanged += new System.EventHandler(this.TextBoxHexadecimalTextChanged);
- this.textBoxHtmlColor.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxHtmlColor.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
- //
- // labelRed
- //
- this.labelRed.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
- this.labelRed.LanguageKey = "colorpicker_red";
- this.labelRed.Location = new System.Drawing.Point(210, 98);
- this.labelRed.Name = "labelRed";
- this.labelRed.Size = new System.Drawing.Size(78, 18);
- this.labelRed.TabIndex = 4;
- this.labelRed.Text = "Red";
- //
- // labelGreen
- //
- this.labelGreen.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
- this.labelGreen.LanguageKey = "colorpicker_green";
- this.labelGreen.Location = new System.Drawing.Point(210, 122);
- this.labelGreen.Name = "labelGreen";
- this.labelGreen.Size = new System.Drawing.Size(78, 18);
- this.labelGreen.TabIndex = 5;
- this.labelGreen.Text = "Green";
- //
- // labelBlue
- //
- this.labelBlue.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
- this.labelBlue.LanguageKey = "colorpicker_blue";
- this.labelBlue.Location = new System.Drawing.Point(210, 146);
- this.labelBlue.Name = "labelBlue";
- this.labelBlue.Size = new System.Drawing.Size(78, 18);
- this.labelBlue.TabIndex = 6;
- this.labelBlue.Text = "Blue";
- //
- // textBoxRed
- //
- this.textBoxRed.Location = new System.Drawing.Point(258, 95);
- this.textBoxRed.Name = "textBoxRed";
- this.textBoxRed.Size = new System.Drawing.Size(30, 20);
- this.textBoxRed.TabIndex = 2;
- this.textBoxRed.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
- this.textBoxRed.Click += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxRed.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
- this.textBoxRed.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxRed.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
- //
- // textBoxGreen
- //
- this.textBoxGreen.Location = new System.Drawing.Point(258, 119);
- this.textBoxGreen.Name = "textBoxGreen";
- this.textBoxGreen.Size = new System.Drawing.Size(30, 20);
- this.textBoxGreen.TabIndex = 3;
- this.textBoxGreen.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
- this.textBoxGreen.Click += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxGreen.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
- this.textBoxGreen.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxGreen.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
- //
- // textBoxBlue
- //
- this.textBoxBlue.Location = new System.Drawing.Point(258, 143);
- this.textBoxBlue.Name = "textBoxBlue";
- this.textBoxBlue.Size = new System.Drawing.Size(30, 20);
- this.textBoxBlue.TabIndex = 4;
- this.textBoxBlue.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
- this.textBoxBlue.Click += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxBlue.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
- this.textBoxBlue.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxBlue.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
- //
- // labelRecentColors
- //
- this.labelRecentColors.LanguageKey = "colorpicker_recentcolors";
- this.labelRecentColors.Location = new System.Drawing.Point(3, 175);
- this.labelRecentColors.Name = "labelRecentColors";
- this.labelRecentColors.Size = new System.Drawing.Size(148, 13);
- this.labelRecentColors.TabIndex = 10;
- this.labelRecentColors.Text = "Recently used colors";
- //
- // textBoxAlpha
- //
- this.textBoxAlpha.Location = new System.Drawing.Point(258, 167);
- this.textBoxAlpha.Name = "textBoxAlpha";
- this.textBoxAlpha.Size = new System.Drawing.Size(30, 20);
- this.textBoxAlpha.TabIndex = 5;
- this.textBoxAlpha.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
- this.textBoxAlpha.Click += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxAlpha.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
- this.textBoxAlpha.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
- this.textBoxAlpha.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
- //
- // labelAlpha
- //
- this.labelAlpha.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
- this.labelAlpha.LanguageKey = "colorpicker_alpha";
- this.labelAlpha.Location = new System.Drawing.Point(210, 170);
- this.labelAlpha.Name = "labelAlpha";
- this.labelAlpha.Size = new System.Drawing.Size(78, 18);
- this.labelAlpha.TabIndex = 11;
- this.labelAlpha.Text = "Alpha";
- //
- // btnApply
- //
- this.btnApply.BackColor = System.Drawing.Color.Transparent;
- this.btnApply.LanguageKey = "colorpicker_apply";
- this.btnApply.Location = new System.Drawing.Point(210, 191);
- this.btnApply.Name = "btnApply";
- this.btnApply.Size = new System.Drawing.Size(78, 23);
- this.btnApply.TabIndex = 12;
- this.btnApply.TabStop = false;
- this.btnApply.Text = "Apply";
- this.btnApply.UseVisualStyleBackColor = false;
- this.btnApply.Click += new System.EventHandler(this.BtnApplyClick);
- //
- // pipette
- //
- this.pipette.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
- this.pipette.Cursor = System.Windows.Forms.Cursors.Arrow;
- this.pipette.Image = ((System.Drawing.Image)(resources.GetObject("pipette.Image")));
- this.pipette.Location = new System.Drawing.Point(255, 30);
- this.pipette.Name = "pipette";
- this.pipette.Size = new System.Drawing.Size(33, 23);
- this.pipette.TabIndex = 13;
- this.pipette.PipetteUsed += new System.EventHandler(this.PipetteUsed);
- //
- // ColorDialog
- //
- this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
- this.ClientSize = new System.Drawing.Size(292, 218);
- this.Controls.Add(this.pipette);
- this.Controls.Add(this.btnApply);
- this.Controls.Add(this.textBoxAlpha);
- this.Controls.Add(this.labelAlpha);
- this.Controls.Add(this.labelRecentColors);
- this.Controls.Add(this.textBoxBlue);
- this.Controls.Add(this.textBoxGreen);
- this.Controls.Add(this.textBoxRed);
- this.Controls.Add(this.labelBlue);
- this.Controls.Add(this.labelGreen);
- this.Controls.Add(this.labelRed);
- this.Controls.Add(this.textBoxHtmlColor);
- this.Controls.Add(this.labelHtmlColor);
- this.Controls.Add(this.colorPanel);
- this.Controls.Add(this.btnTransparent);
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
- this.LanguageKey = "colorpicker_title";
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "ColorDialog";
- this.ShowIcon = false;
- this.ShowInTaskbar = false;
- this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
- this.Text = "Color picker";
- this.ResumeLayout(false);
- this.PerformLayout();
-
- }
- private GreenshotLabel labelRed;
- private GreenshotLabel labelGreen;
- private GreenshotLabel labelBlue;
- private System.Windows.Forms.TextBox textBoxHtmlColor;
- private GreenshotLabel labelRecentColors;
- private GreenshotLabel labelAlpha;
- private GreenshotLabel labelHtmlColor;
- private GreenshotButton btnApply;
- private System.Windows.Forms.TextBox textBoxAlpha;
- private System.Windows.Forms.TextBox textBoxRed;
- private System.Windows.Forms.TextBox textBoxGreen;
- private System.Windows.Forms.TextBox textBoxBlue;
- private System.Windows.Forms.Panel colorPanel;
- private GreenshotButton btnTransparent;
- private Greenshot.Controls.Pipette pipette;
-
-
-
-
-
- }
-}
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: https://getgreenshot.org/
+ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using Greenshot.Base.Controls;
+using Greenshot.Editor.Controls;
+
+namespace Greenshot.Editor.Forms {
+ public partial class ColorDialog {
+ ///
+ /// Designer variable used to keep track of non-visual components.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Disposes resources used by the form.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing) {
+ if (components != null) {
+ components.Dispose();
+ }
+ }
+ base.Dispose(disposing);
+ }
+
+ ///
+ /// This method is required for Windows Forms designer support.
+ /// Do not change the method contents inside the source code editor. The Forms designer might
+ /// not be able to load this method if it was changed manually.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ColorDialog));
+ this.btnTransparent = new GreenshotButton();
+ this.colorPanel = new System.Windows.Forms.Panel();
+ this.labelHtmlColor = new GreenshotLabel();
+ this.textBoxHtmlColor = new System.Windows.Forms.TextBox();
+ this.labelRed = new GreenshotLabel();
+ this.labelGreen = new GreenshotLabel();
+ this.labelBlue = new GreenshotLabel();
+ this.textBoxRed = new System.Windows.Forms.TextBox();
+ this.textBoxGreen = new System.Windows.Forms.TextBox();
+ this.textBoxBlue = new System.Windows.Forms.TextBox();
+ this.labelRecentColors = new GreenshotLabel();
+ this.textBoxAlpha = new System.Windows.Forms.TextBox();
+ this.labelAlpha = new GreenshotLabel();
+ this.btnApply = new GreenshotButton();
+ this.pipette = new Pipette();
+ this.SuspendLayout();
+ //
+ // btnTransparent
+ //
+ this.btnTransparent.BackColor = System.Drawing.Color.Transparent;
+ this.btnTransparent.LanguageKey = "colorpicker_transparent";
+ this.btnTransparent.Location = new System.Drawing.Point(210, 4);
+ this.btnTransparent.Name = "btnTransparent";
+ this.btnTransparent.Size = new System.Drawing.Size(78, 23);
+ this.btnTransparent.TabIndex = 0;
+ this.btnTransparent.TabStop = false;
+ this.btnTransparent.Text = "Transparent";
+ this.btnTransparent.UseVisualStyleBackColor = false;
+ this.btnTransparent.Click += new System.EventHandler(this.BtnTransparentClick);
+ //
+ // colorPanel
+ //
+ this.colorPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.colorPanel.Location = new System.Drawing.Point(213, 30);
+ this.colorPanel.Name = "colorPanel";
+ this.colorPanel.Size = new System.Drawing.Size(33, 23);
+ this.colorPanel.TabIndex = 1;
+ //
+ // labelHtmlColor
+ //
+ this.labelHtmlColor.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
+ this.labelHtmlColor.LanguageKey = "colorpicker_htmlcolor";
+ this.labelHtmlColor.Location = new System.Drawing.Point(210, 57);
+ this.labelHtmlColor.Name = "labelHtmlColor";
+ this.labelHtmlColor.Size = new System.Drawing.Size(78, 17);
+ this.labelHtmlColor.TabIndex = 2;
+ this.labelHtmlColor.Text = "HTML color";
+ //
+ // textBoxHtmlColor
+ //
+ this.textBoxHtmlColor.Location = new System.Drawing.Point(210, 71);
+ this.textBoxHtmlColor.Name = "textBoxHtmlColor";
+ this.textBoxHtmlColor.Size = new System.Drawing.Size(78, 20);
+ this.textBoxHtmlColor.TabIndex = 1;
+ this.textBoxHtmlColor.Click += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxHtmlColor.TextChanged += new System.EventHandler(this.TextBoxHexadecimalTextChanged);
+ this.textBoxHtmlColor.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxHtmlColor.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
+ //
+ // labelRed
+ //
+ this.labelRed.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
+ this.labelRed.LanguageKey = "colorpicker_red";
+ this.labelRed.Location = new System.Drawing.Point(210, 98);
+ this.labelRed.Name = "labelRed";
+ this.labelRed.Size = new System.Drawing.Size(78, 18);
+ this.labelRed.TabIndex = 4;
+ this.labelRed.Text = "Red";
+ //
+ // labelGreen
+ //
+ this.labelGreen.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
+ this.labelGreen.LanguageKey = "colorpicker_green";
+ this.labelGreen.Location = new System.Drawing.Point(210, 122);
+ this.labelGreen.Name = "labelGreen";
+ this.labelGreen.Size = new System.Drawing.Size(78, 18);
+ this.labelGreen.TabIndex = 5;
+ this.labelGreen.Text = "Green";
+ //
+ // labelBlue
+ //
+ this.labelBlue.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
+ this.labelBlue.LanguageKey = "colorpicker_blue";
+ this.labelBlue.Location = new System.Drawing.Point(210, 146);
+ this.labelBlue.Name = "labelBlue";
+ this.labelBlue.Size = new System.Drawing.Size(78, 18);
+ this.labelBlue.TabIndex = 6;
+ this.labelBlue.Text = "Blue";
+ //
+ // textBoxRed
+ //
+ this.textBoxRed.Location = new System.Drawing.Point(258, 95);
+ this.textBoxRed.Name = "textBoxRed";
+ this.textBoxRed.Size = new System.Drawing.Size(30, 20);
+ this.textBoxRed.TabIndex = 2;
+ this.textBoxRed.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.textBoxRed.Click += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxRed.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
+ this.textBoxRed.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxRed.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
+ //
+ // textBoxGreen
+ //
+ this.textBoxGreen.Location = new System.Drawing.Point(258, 119);
+ this.textBoxGreen.Name = "textBoxGreen";
+ this.textBoxGreen.Size = new System.Drawing.Size(30, 20);
+ this.textBoxGreen.TabIndex = 3;
+ this.textBoxGreen.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.textBoxGreen.Click += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxGreen.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
+ this.textBoxGreen.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxGreen.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
+ //
+ // textBoxBlue
+ //
+ this.textBoxBlue.Location = new System.Drawing.Point(258, 143);
+ this.textBoxBlue.Name = "textBoxBlue";
+ this.textBoxBlue.Size = new System.Drawing.Size(30, 20);
+ this.textBoxBlue.TabIndex = 4;
+ this.textBoxBlue.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.textBoxBlue.Click += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxBlue.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
+ this.textBoxBlue.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxBlue.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
+ //
+ // labelRecentColors
+ //
+ this.labelRecentColors.LanguageKey = "colorpicker_recentcolors";
+ this.labelRecentColors.Location = new System.Drawing.Point(3, 175);
+ this.labelRecentColors.Name = "labelRecentColors";
+ this.labelRecentColors.Size = new System.Drawing.Size(148, 13);
+ this.labelRecentColors.TabIndex = 10;
+ this.labelRecentColors.Text = "Recently used colors";
+ //
+ // textBoxAlpha
+ //
+ this.textBoxAlpha.Location = new System.Drawing.Point(258, 167);
+ this.textBoxAlpha.Name = "textBoxAlpha";
+ this.textBoxAlpha.Size = new System.Drawing.Size(30, 20);
+ this.textBoxAlpha.TabIndex = 5;
+ this.textBoxAlpha.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.textBoxAlpha.Click += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxAlpha.TextChanged += new System.EventHandler(this.TextBoxRgbTextChanged);
+ this.textBoxAlpha.GotFocus += new System.EventHandler(this.TextBoxGotFocus);
+ this.textBoxAlpha.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown);
+ //
+ // labelAlpha
+ //
+ this.labelAlpha.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World);
+ this.labelAlpha.LanguageKey = "colorpicker_alpha";
+ this.labelAlpha.Location = new System.Drawing.Point(210, 170);
+ this.labelAlpha.Name = "labelAlpha";
+ this.labelAlpha.Size = new System.Drawing.Size(78, 18);
+ this.labelAlpha.TabIndex = 11;
+ this.labelAlpha.Text = "Alpha";
+ //
+ // btnApply
+ //
+ this.btnApply.BackColor = System.Drawing.Color.Transparent;
+ this.btnApply.LanguageKey = "colorpicker_apply";
+ this.btnApply.Location = new System.Drawing.Point(210, 191);
+ this.btnApply.Name = "btnApply";
+ this.btnApply.Size = new System.Drawing.Size(78, 23);
+ this.btnApply.TabIndex = 12;
+ this.btnApply.TabStop = false;
+ this.btnApply.Text = "Apply";
+ this.btnApply.UseVisualStyleBackColor = false;
+ this.btnApply.Click += new System.EventHandler(this.BtnApplyClick);
+ //
+ // pipette
+ //
+ this.pipette.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.pipette.Cursor = System.Windows.Forms.Cursors.Arrow;
+ this.pipette.Image = ((System.Drawing.Image)(resources.GetObject("pipette.Image")));
+ this.pipette.Location = new System.Drawing.Point(255, 30);
+ this.pipette.Name = "pipette";
+ this.pipette.Size = new System.Drawing.Size(33, 23);
+ this.pipette.TabIndex = 13;
+ this.pipette.PipetteUsed += new System.EventHandler(this.PipetteUsed);
+ //
+ // ColorDialog
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.ClientSize = new System.Drawing.Size(292, 218);
+ this.Controls.Add(this.pipette);
+ this.Controls.Add(this.btnApply);
+ this.Controls.Add(this.textBoxAlpha);
+ this.Controls.Add(this.labelAlpha);
+ this.Controls.Add(this.labelRecentColors);
+ this.Controls.Add(this.textBoxBlue);
+ this.Controls.Add(this.textBoxGreen);
+ this.Controls.Add(this.textBoxRed);
+ this.Controls.Add(this.labelBlue);
+ this.Controls.Add(this.labelGreen);
+ this.Controls.Add(this.labelRed);
+ this.Controls.Add(this.textBoxHtmlColor);
+ this.Controls.Add(this.labelHtmlColor);
+ this.Controls.Add(this.colorPanel);
+ this.Controls.Add(this.btnTransparent);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.LanguageKey = "colorpicker_title";
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "ColorDialog";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.Text = "Color picker";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+ private GreenshotLabel labelRed;
+ private GreenshotLabel labelGreen;
+ private GreenshotLabel labelBlue;
+ private System.Windows.Forms.TextBox textBoxHtmlColor;
+ private GreenshotLabel labelRecentColors;
+ private GreenshotLabel labelAlpha;
+ private GreenshotLabel labelHtmlColor;
+ private GreenshotButton btnApply;
+ private System.Windows.Forms.TextBox textBoxAlpha;
+ private System.Windows.Forms.TextBox textBoxRed;
+ private System.Windows.Forms.TextBox textBoxGreen;
+ private System.Windows.Forms.TextBox textBoxBlue;
+ private System.Windows.Forms.Panel colorPanel;
+ private GreenshotButton btnTransparent;
+ private Pipette pipette;
+
+
+
+
+
+ }
+}
diff --git a/src/Greenshot/Forms/ColorDialog.cs b/src/Greenshot.Editor/Forms/ColorDialog.cs
similarity index 95%
rename from src/Greenshot/Forms/ColorDialog.cs
rename to src/Greenshot.Editor/Forms/ColorDialog.cs
index 14f5e5022..50211782f 100644
--- a/src/Greenshot/Forms/ColorDialog.cs
+++ b/src/Greenshot.Editor/Forms/ColorDialog.cs
@@ -1,280 +1,280 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: https://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Globalization;
-using System.Threading;
-using System.Windows.Forms;
-using Greenshot.Base.IniFile;
-using Greenshot.Configuration;
-using Greenshot.Controls;
-
-namespace Greenshot.Forms
-{
- ///
- /// Description of ColorDialog.
- ///
- public partial class ColorDialog : BaseForm
- {
- private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection();
- private static ColorDialog _instance;
-
- public ColorDialog()
- {
- SuspendLayout();
- InitializeComponent();
- SuspendLayout();
- CreateColorPalette(5, 5, 15, 15);
- CreateLastUsedColorButtonRow(5, 190, 15, 15);
- ResumeLayout();
- UpdateRecentColorsButtonRow();
- _instance = this;
- }
-
- public static ColorDialog GetInstance() => _instance;
-
- private readonly List
public class PickerDestination : AbstractDestination
{
- public const string DESIGNATION = "Picker";
-
- public override string Designation => DESIGNATION;
+ public override string Designation => nameof(WellKnownDestinations.Picker);
public override string Description => Language.GetString(LangKey.settings_destination_picker);
diff --git a/src/Greenshot/Destinations/PrinterDestination.cs b/src/Greenshot/Destinations/PrinterDestination.cs
index 6a85a1e83..7265c4576 100644
--- a/src/Greenshot/Destinations/PrinterDestination.cs
+++ b/src/Greenshot/Destinations/PrinterDestination.cs
@@ -24,6 +24,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
+using Greenshot.Base;
using Greenshot.Base.Core;
using Greenshot.Base.Interfaces;
using Greenshot.Configuration;
@@ -36,7 +37,6 @@ namespace Greenshot.Destinations
///
public class PrinterDestination : AbstractDestination
{
- public const string DESIGNATION = "Printer";
private readonly string _printerName;
public PrinterDestination()
@@ -48,7 +48,7 @@ namespace Greenshot.Destinations
_printerName = printerName;
}
- public override string Designation => DESIGNATION;
+ public override string Designation => nameof(WellKnownDestinations.Printer);
public override string Description
{
diff --git a/src/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs
index b0e9781d0..a801cc63e 100644
--- a/src/Greenshot/Forms/AboutForm.cs
+++ b/src/Greenshot/Forms/AboutForm.cs
@@ -31,7 +31,6 @@ using System.Windows.Forms;
using Greenshot.Base.Core;
using Greenshot.Base.IniFile;
using Greenshot.Configuration;
-using Greenshot.Helpers;
using log4net;
namespace Greenshot.Forms
@@ -44,10 +43,10 @@ namespace Greenshot.Forms
private static readonly ILog Log = LogManager.GetLogger(typeof(AboutForm));
private Bitmap _bitmap;
private readonly ColorAnimator _backgroundAnimation;
- private readonly List _pixels = new List();
- private readonly List _colorFlow = new List();
- private readonly List _pixelColors = new List();
- private readonly Random _rand = new Random();
+ private readonly List _pixels = new();
+ private readonly List _colorFlow = new();
+ private readonly List _pixelColors = new();
+ private readonly Random _rand = new();
private readonly Color _backColor = Color.FromArgb(61, 61, 61);
private readonly Color _pixelColor = Color.FromArgb(138, 255, 0);
@@ -117,7 +116,7 @@ namespace Greenshot.Forms
// 18 19 20 21 22 23
// The order in which we draw the dots & flow the colors.
- private readonly List _flowOrder = new List{ 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 };
+ private readonly List _flowOrder = new() { 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 };
///
/// Cleanup all the allocated resources
@@ -177,8 +176,7 @@ namespace Greenshot.Forms
if (IsTerminalServerSession)
{
// No animation
- pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic,
- EasingMode.EaseIn);
+ pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, EasingMode.EaseIn);
}
else
{
diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs
index f06419949..6176c732e 100644
--- a/src/Greenshot/Forms/CaptureForm.cs
+++ b/src/Greenshot/Forms/CaptureForm.cs
@@ -19,8 +19,6 @@
* along with this program. If not, see .
*/
-using Greenshot.Drawing;
-using Greenshot.Helpers;
using log4net;
using System;
using System.Collections.Generic;
@@ -38,6 +36,7 @@ using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Ocr;
using Greenshot.Base.UnmanagedHelpers;
+using Greenshot.Editor.Helpers;
namespace Greenshot.Forms
{
@@ -204,8 +203,7 @@ namespace Greenshot.Forms
if (isOn)
{
// Initialize the zoom with a invalid position
- _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic,
- EasingMode.EaseOut);
+ _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut);
VerifyZoomAnimation(_cursorPos, false);
}
else
@@ -270,16 +268,6 @@ namespace Greenshot.Forms
_capture.CursorVisible = !_capture.CursorVisible;
Invalidate();
break;
- //// TODO: Enable when the screen capture code works reliable
- //case Keys.V:
- // // Video
- // if (capture.CaptureDetails.CaptureMode != CaptureMode.Video) {
- // capture.CaptureDetails.CaptureMode = CaptureMode.Video;
- // } else {
- // capture.CaptureDetails.CaptureMode = captureMode;
- // }
- // Invalidate();
- // break;
case Keys.Z:
if (_captureMode == CaptureMode.Region)
{
@@ -309,8 +297,7 @@ namespace Greenshot.Forms
// "Fade out" Zoom
InitializeZoomer(false);
// "Fade in" window
- _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic,
- EasingMode.EaseOut);
+ _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut);
_captureRect = Rectangle.Empty;
Invalidate();
break;
@@ -670,7 +657,7 @@ namespace Greenshot.Forms
}
}
- // always animate the Window area through to the last frame, so we see the fade-in/out untill the end
+ // always animate the Window area through to the last frame, so we see the fade-in/out until the end
// Using a safety "offset" to make sure the text is invalidated too
const int safetySize = 30;
// Check if the animation needs to be drawn
@@ -717,34 +704,21 @@ namespace Greenshot.Forms
foreach (var line in ocrInfo.Lines)
{
var lineBounds = line.CalculatedBounds;
- if (!lineBounds.IsEmpty)
+ if (lineBounds.IsEmpty)
{
- if (_mouseDown)
- {
- // Highlight the text which is selected
- if (lineBounds.IntersectsWith(_captureRect))
- {
- foreach (var word in line.Words)
- {
- if (word.Bounds.IntersectsWith(_captureRect))
- {
- if (invalidateRectangle.IsEmpty)
- {
- invalidateRectangle = word.Bounds;
- }
- else
- {
- invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds);
- }
- }
- }
- }
- }
- else if (lineBounds.Contains(_mouseMovePos))
+ continue;
+ }
+ if (_mouseDown)
+ {
+ // Highlight the text which is selected
+ if (lineBounds.IntersectsWith(_captureRect))
{
foreach (var word in line.Words)
{
- if (!word.Bounds.Contains(_mouseMovePos)) continue;
+ if (!word.Bounds.IntersectsWith(_captureRect))
+ {
+ continue;
+ }
if (invalidateRectangle.IsEmpty)
{
invalidateRectangle = word.Bounds;
@@ -753,11 +727,26 @@ namespace Greenshot.Forms
{
invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds);
}
-
- break;
}
}
}
+ else if (lineBounds.Contains(_mouseMovePos))
+ {
+ foreach (var word in line.Words)
+ {
+ if (!word.Bounds.Contains(_mouseMovePos)) continue;
+ if (invalidateRectangle.IsEmpty)
+ {
+ invalidateRectangle = word.Bounds;
+ }
+ else
+ {
+ invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds);
+ }
+
+ break;
+ }
+ }
}
if (!invalidateRectangle.IsEmpty)
@@ -796,38 +785,39 @@ namespace Greenshot.Forms
Rectangle targetRectangle = _zoomAnimator.Final;
targetRectangle.Offset(pos);
- if (!screenBounds.Contains(targetRectangle) || (!allowZoomOverCaptureRect && _captureRect.IntersectsWith(targetRectangle)))
+ if (screenBounds.Contains(targetRectangle) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(targetRectangle)))
{
- Point destinationLocation = Point.Empty;
- Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height);
- Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height);
- Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height);
- Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height);
- if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br)))
- {
- destinationLocation = new Point(zoomOffset.X, zoomOffset.Y);
- }
- else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl)))
- {
- destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y);
- }
- else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr)))
- {
- destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width);
- }
- else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl)))
- {
- destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width);
- }
+ return;
+ }
+ Point destinationLocation = Point.Empty;
+ Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height);
+ Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height);
+ Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height);
+ Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height);
+ if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br)))
+ {
+ destinationLocation = new Point(zoomOffset.X, zoomOffset.Y);
+ }
+ else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl)))
+ {
+ destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y);
+ }
+ else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr)))
+ {
+ destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width);
+ }
+ else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl)))
+ {
+ destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width);
+ }
- if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect)
- {
- VerifyZoomAnimation(pos, true);
- }
- else
- {
- _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize));
- }
+ if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect)
+ {
+ VerifyZoomAnimation(pos, true);
+ }
+ else
+ {
+ _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize));
}
}
@@ -877,8 +867,7 @@ namespace Greenshot.Forms
}
else
{
- graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height,
- GraphicsUnit.Pixel, attributes);
+ graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes);
}
}
@@ -964,33 +953,37 @@ namespace Greenshot.Forms
foreach (var line in ocrInfo.Lines)
{
var lineBounds = line.CalculatedBounds;
- if (!lineBounds.IsEmpty)
+ if (lineBounds.IsEmpty)
{
- graphics.DrawRectangle(pen, line.CalculatedBounds);
- if (_mouseDown)
- {
- // Highlight the text which is selected
- if (lineBounds.IntersectsWith(_captureRect))
- {
- foreach (var word in line.Words)
- {
- if (word.Bounds.IntersectsWith(_captureRect))
- {
- graphics.FillRectangle(highlightTextBrush, word.Bounds);
- }
- }
- }
- }
- else if (lineBounds.Contains(_mouseMovePos))
+ continue;
+ }
+ graphics.DrawRectangle(pen, line.CalculatedBounds);
+ if (_mouseDown)
+ {
+ // Highlight the text which is selected
+ if (lineBounds.IntersectsWith(_captureRect))
{
foreach (var word in line.Words)
{
- if (!word.Bounds.Contains(_mouseMovePos)) continue;
- graphics.FillRectangle(highlightTextBrush, word.Bounds);
- break;
+ if (word.Bounds.IntersectsWith(_captureRect))
+ {
+ graphics.FillRectangle(highlightTextBrush, word.Bounds);
+ }
}
}
}
+ else if (lineBounds.Contains(_mouseMovePos))
+ {
+ foreach (var word in line.Words)
+ {
+ if (!word.Bounds.Contains(_mouseMovePos))
+ {
+ continue;
+ }
+ graphics.FillRectangle(highlightTextBrush, word.Bounds);
+ break;
+ }
+ }
}
}
diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs
index c95a9e66a..b775149cb 100644
--- a/src/Greenshot/Forms/MainForm.cs
+++ b/src/Greenshot/Forms/MainForm.cs
@@ -32,26 +32,31 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
+using Greenshot.Base;
using Greenshot.Base.Controls;
using Greenshot.Base.Core;
+using Greenshot.Base.Core.Enums;
+using Greenshot.Base.Help;
using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Plugin;
using Greenshot.Base.UnmanagedHelpers;
using Greenshot.Configuration;
using Greenshot.Destinations;
-using Greenshot.Drawing;
-using Greenshot.Help;
+using Greenshot.Editor.Destinations;
+using Greenshot.Editor.Drawing;
+using Greenshot.Editor.Forms;
using Greenshot.Helpers;
+using Greenshot.Processors;
using log4net;
using Timer = System.Timers.Timer;
namespace Greenshot.Forms
{
///
- /// Description of MainForm.
+ /// This is the MainForm, the shell of Greenshot
///
- public partial class MainForm : BaseForm
+ public partial class MainForm : BaseForm, IGreenshotMainForm, ICaptureHelper
{
private static ILog LOG;
private static ResourceMutex _applicationMutex;
@@ -336,17 +341,18 @@ namespace Greenshot.Forms
private static void FreeMutex()
{
// Remove the application mutex
- if (_applicationMutex != null)
+ if (_applicationMutex == null)
{
- try
- {
- _applicationMutex.Dispose();
- _applicationMutex = null;
- }
- catch (Exception ex)
- {
- LOG.Error("Error releasing Mutex!", ex);
- }
+ return;
+ }
+ try
+ {
+ _applicationMutex.Dispose();
+ _applicationMutex = null;
+ }
+ catch (Exception ex)
+ {
+ LOG.Error("Error releasing Mutex!", ex);
}
}
@@ -376,6 +382,8 @@ namespace Greenshot.Forms
SimpleServiceProvider.Current.AddService