diff --git a/Greenshot/App.config b/Greenshot/App.config deleted file mode 100644 index f15ae706e..000000000 --- a/Greenshot/App.config +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/Greenshot/Configuration/EditorConfiguration.cs b/Greenshot/Configuration/EditorConfiguration.cs deleted file mode 100644 index 019ea9ef6..000000000 --- a/Greenshot/Configuration/EditorConfiguration.cs +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Drawing; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -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; - } - } -} diff --git a/Greenshot/Configuration/LanguageKeys.cs b/Greenshot/Configuration/LanguageKeys.cs deleted file mode 100644 index a668218eb..000000000 --- a/Greenshot/Configuration/LanguageKeys.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.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 - } -} diff --git a/Greenshot/Controls/BindableToolStripDropDownButton.cs b/Greenshot/Controls/BindableToolStripDropDownButton.cs deleted file mode 100644 index 4071d6b81..000000000 --- a/Greenshot/Controls/BindableToolStripDropDownButton.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.ComponentModel; -using System.Windows.Forms; -using GreenshotPlugin.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")); - } - } - } -} diff --git a/Greenshot/Controls/ColorButton.cs b/Greenshot/Controls/ColorButton.cs deleted file mode 100644 index fe31d2e11..000000000 --- a/Greenshot/Controls/ColorButton.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.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")); - } - } -} diff --git a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs deleted file mode 100644 index e5ebf5478..000000000 --- a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Core; -using System.Drawing; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; - -namespace Greenshot.Controls { - /// - /// ToolStripProfessionalRenderer which draws the Check correctly when the icons are larger - /// - public class ContextMenuToolStripProfessionalRenderer : ToolStripProfessionalRenderer { - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static Image _scaledCheckbox; - - protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) { - if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) { - _scaledCheckbox?.Dispose(); - _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null); - } - Rectangle old = e.ImageRectangle; - ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height)); - base.OnRenderItemCheck(clone); - } - } -} diff --git a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs deleted file mode 100644 index d559d771b..000000000 --- a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Windows.Forms; - -namespace Greenshot.Controls { - /// - /// Prevent having a gradient background in the toolstrip, and the overflow button - /// See: http://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: http://stackoverflow.com/a/16926979 and http://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 - } - } -} diff --git a/Greenshot/Controls/FontFamilyComboBox.cs b/Greenshot/Controls/FontFamilyComboBox.cs deleted file mode 100644 index d37244eab..000000000 --- a/Greenshot/Controls/FontFamilyComboBox.cs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; -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")); - } - } -} diff --git a/Greenshot/Controls/MenuStripEx.cs b/Greenshot/Controls/MenuStripEx.cs deleted file mode 100644 index 7dda22931..000000000 --- a/Greenshot/Controls/MenuStripEx.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Windows.Forms; -using GreenshotPlugin.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: http://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; - } - } - } -} diff --git a/Greenshot/Controls/Pipette.cs b/Greenshot/Controls/Pipette.cs deleted file mode 100644 index ca7333d81..000000000 --- a/Greenshot/Controls/Pipette.cs +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Windows.Forms; -using Greenshot.Forms; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; -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; - } - } -} diff --git a/Greenshot/Controls/ToolStripColorButton.cs b/Greenshot/Controls/ToolStripColorButton.cs deleted file mode 100644 index 951e117fd..000000000 --- a/Greenshot/Controls/ToolStripColorButton.cs +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.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")); - } - } -} diff --git a/Greenshot/Controls/ToolStripEx.cs b/Greenshot/Controls/ToolStripEx.cs deleted file mode 100644 index 7d2ca63ed..000000000 --- a/Greenshot/Controls/ToolStripEx.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.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: http://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; - } - } - } -} diff --git a/Greenshot/Controls/ToolStripNumericUpDown.cs b/Greenshot/Controls/ToolStripNumericUpDown.cs deleted file mode 100644 index 13652fc41..000000000 --- a/Greenshot/Controls/ToolStripNumericUpDown.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -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")); - } - } -} diff --git a/Greenshot/Destinations/ClipboardDestination.cs b/Greenshot/Destinations/ClipboardDestination.cs deleted file mode 100644 index a1172ede4..000000000 --- a/Greenshot/Destinations/ClipboardDestination.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of ClipboardDestination. - /// - public class ClipboardDestination : AbstractDestination { - public const string DESIGNATION = "Clipboard"; - - public override string Designation { - get { - return DESIGNATION; - } - } - - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_clipboard); - } - } - public override int Priority { - get { - return 2; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.C; - } - } - - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Clipboard.Image"); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - try { - ClipboardHelper.SetClipboardData(surface); - exportInformation.ExportMade = true; - } catch (Exception) { - // TODO: Change to general logic in ProcessExport - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetString(LangKey.editor_clipboardfailed)); - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs deleted file mode 100644 index 220359238..000000000 --- a/Greenshot/Destinations/EditorDestination.cs +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Drawing; -using Greenshot.Configuration; -using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.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; - } - } -} diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs deleted file mode 100644 index 326e27e9c..000000000 --- a/Greenshot/Destinations/EmailDestination.cs +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using Microsoft.Win32; - -namespace Greenshot.Destinations { - /// - /// Description of EmailDestination. - /// - public class EmailDestination : AbstractDestination { - private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); - private static bool _isActiveFlag; - private static string _mapiClient; - public const string DESIGNATION = "EMail"; - - static EmailDestination() { - // Logic to decide what email implementation we use - _mapiClient = RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); - if (!string.IsNullOrEmpty(_mapiClient)) { - // Active as we have a MAPI client, can be disabled later - _isActiveFlag = true; - } - } - - public override string Designation => DESIGNATION; - - public override string Description { - get - { - // Make sure there is some kind of "mail" name - return _mapiClient ??= Language.GetString(LangKey.editor_email); - } - } - - public override int Priority => 3; - - public override bool IsActive { - get { - if (_isActiveFlag) { - // Disable if the office plugin is installed and the client is outlook - // TODO: Change this! It always creates an exception, as the plugin has not been loaded the type is not there :( - var outlookDestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin", false); - if (outlookDestination != null && _mapiClient.ToLower().Contains("microsoft outlook")) { - _isActiveFlag = false; - } - } - return base.IsActive && _isActiveFlag; - } - } - - public override Keys EditorShortcutKeys => Keys.Control | Keys.E; - - public override Image DisplayIcon => MailIcon; - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - MapiMailMessage.SendImage(surface, captureDetails); - exportInformation.ExportMade = true; - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} \ No newline at end of file diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs deleted file mode 100644 index d6e89c0d5..000000000 --- a/Greenshot/Destinations/FileDestination.cs +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using System.Windows.Forms; - -using Greenshot.Configuration; -using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Controls; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using log4net; - -namespace Greenshot.Destinations { - /// - /// Description of FileSaveAsDestination. - /// - public class FileDestination : AbstractDestination { - private static readonly ILog Log = LogManager.GetLogger(typeof(FileDestination)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileNoDialog"; - - public override string Designation => DESIGNATION; - - public override string Description => Language.GetString(LangKey.quicksettings_destination_file); - - public override int Priority => 0; - - public override Keys EditorShortcutKeys => Keys.Control | Keys.S; - - public override Image DisplayIcon => GreenshotResources.GetImage("Save.Image"); - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool outputMade; - bool overwrite; - string fullPath; - // Get output settings from the configuration - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); - - if (captureDetails?.Filename != null) { - // As we save a pre-selected file, allow to overwrite. - overwrite = true; - Log.InfoFormat("Using previous filename"); - fullPath = captureDetails.Filename; - outputSettings.Format = ImageOutput.FormatForFilename(fullPath); - } else { - fullPath = CreateNewFilename(captureDetails); - // As we generate a file, the configuration tells us if we allow to overwrite - overwrite = CoreConfig.OutputFileAllowOverwrite; - } - if (CoreConfig.OutputFilePromptQuality) { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } - - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 - try { - ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - outputMade = true; - } catch (ArgumentException ex1) { - // Our generated filename exists, display 'save-as' - Log.InfoFormat("Not overwriting: {0}", ex1.Message); - // when we don't allow to overwrite present a new SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } catch (Exception ex2) { - Log.Error("Error saving screenshot!", ex2); - // Show the problem - MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); - // when save failed we present a SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } - // Don't overwrite filename if no output is made - if (outputMade) { - exportInformation.ExportMade = true; - exportInformation.Filepath = fullPath; - if (captureDetails != null) - { - captureDetails.Filename = fullPath; - } - CoreConfig.OutputFileAsFullpath = fullPath; - } - - ProcessExport(exportInformation, surface); - return exportInformation; - } - - private static string CreateNewFilename(ICaptureDetails captureDetails) { - string fullPath; - Log.InfoFormat("Creating new filename"); - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern)) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, CoreConfig.OutputFileFormat, captureDetails); - CoreConfig.ValidateAndCorrectOutputFilePath(); - string filepath = FilenameHelper.FillVariables(CoreConfig.OutputFilePath, false); - try { - fullPath = Path.Combine(filepath, filename); - } catch (ArgumentException) { - // configured filename or path not valid, show error message... - Log.InfoFormat("Generated path or filename not valid: {0}, {1}", filepath, filename); - - MessageBox.Show(Language.GetString(LangKey.error_save_invalid_chars), Language.GetString(LangKey.error)); - // ... lets get the pattern fixed.... - var dialogResult = new SettingsForm().ShowDialog(); - if (dialogResult == DialogResult.OK) { - // ... OK -> then try again: - fullPath = CreateNewFilename(captureDetails); - } else { - // ... cancelled. - fullPath = null; - } - - } - return fullPath; - } - } -} diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/Greenshot/Destinations/FileWithDialogDestination.cs deleted file mode 100644 index b378f5f34..000000000 --- a/Greenshot/Destinations/FileWithDialogDestination.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of FileWithDialog. - /// - public class FileWithDialogDestination : AbstractDestination { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileDialog"; - - public override string Designation { - get { - return DESIGNATION; - } - } - - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_fileas); - } - } - - public override int Priority { - get { - return 0; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.S; - } - } - - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Save.Image"); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Bug #2918756 don't overwrite path if SaveWithDialog returns null! - var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); - if (savedTo != null) { - exportInformation.ExportMade = true; - exportInformation.Filepath = savedTo; - captureDetails.Filename = savedTo; - conf.OutputFileAsFullpath = savedTo; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/PickerDestination.cs b/Greenshot/Destinations/PickerDestination.cs deleted file mode 100644 index e7ea94c83..000000000 --- a/Greenshot/Destinations/PickerDestination.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections.Generic; -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// The PickerDestination shows a context menu with all possible destinations, so the user can "pick" one - /// - public class PickerDestination : AbstractDestination { - public const string DESIGNATION = "Picker"; - - public override string Designation => DESIGNATION; - - public override string Description => Language.GetString(LangKey.settings_destination_picker); - - public override int Priority => 1; - - - /// - /// Export the capture with the destination picker - /// - /// Did the user select this destination? - /// Surface to export - /// Details of the capture - /// true if export was made - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - List destinations = new List(); - - foreach(var destination in SimpleServiceProvider.Current.GetAllInstances()) { - if ("Picker".Equals(destination.Designation)) { - continue; - } - if (!destination.IsActive) { - continue; - } - destinations.Add(destination); - } - - // No Processing, this is done in the selected destination (if anything was selected) - return ShowPickerMenu(true, surface, captureDetails, destinations); - } - } -} diff --git a/Greenshot/Destinations/PrinterDestination.cs b/Greenshot/Destinations/PrinterDestination.cs deleted file mode 100644 index 3a45268e2..000000000 --- a/Greenshot/Destinations/PrinterDestination.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Printing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of PrinterDestination. - /// - public class PrinterDestination : AbstractDestination { - public const string DESIGNATION = "Printer"; - private readonly string _printerName; - - public PrinterDestination() { - } - - public PrinterDestination(string printerName) { - _printerName = printerName; - } - public override string Designation => DESIGNATION; - - public override string Description { - get { - if (_printerName != null) { - return Language.GetString(LangKey.settings_destination_printer) + " - " + _printerName; - } - return Language.GetString(LangKey.settings_destination_printer); - } - } - - public override int Priority => 2; - - public override Keys EditorShortcutKeys => Keys.Control | Keys.P; - - public override Image DisplayIcon => GreenshotResources.GetImage("Printer.Image"); - - public override bool IsDynamic => true; - - /// - /// Create destinations for all the installed printers - /// - /// IEnumerable of IDestination - public override IEnumerable DynamicDestinations() { - PrinterSettings settings = new PrinterSettings(); - string defaultPrinter = settings.PrinterName; - List printers = new List(); - - foreach (string printer in PrinterSettings.InstalledPrinters) { - printers.Add(printer); - } - printers.Sort(delegate(string p1, string p2) { - if(defaultPrinter.Equals(p1)) { - return -1; - } - if(defaultPrinter.Equals(p2)) { - return 1; - } - return string.Compare(p1, p2, StringComparison.Ordinal); - }); - foreach(string printer in printers) { - yield return new PrinterDestination(printer); - } - } - - /// - /// Export the capture to the printer - /// - /// - /// - /// - /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - PrinterSettings printerSettings; - if (!string.IsNullOrEmpty(_printerName)) - { - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintTo(_printerName); - } else if (!manuallyInitiated) { - PrinterSettings settings = new PrinterSettings(); - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintTo(settings.PrinterName); - } else - { - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintWithDialog(); - } - if (printerSettings != null) { - exportInformation.ExportMade = true; - } - - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs deleted file mode 100644 index 5461b4df4..000000000 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.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) - { - } - } -} diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs deleted file mode 100644 index c8ef3ea22..000000000 --- a/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Helpers; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.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); - } - } -} diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs deleted file mode 100644 index b2e7261a9..000000000 --- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Helpers; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.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); - } - } -} diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs deleted file mode 100644 index e0d0bbf13..000000000 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// - /// This implements the special "gripper" for the Speech-Bubble tail - /// - public class TargetAdorner : AbstractAdorner - { - - public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) - { - Location = location; - } - - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.MOVING; - } - - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.MOVING) - { - return; - } - - Owner.Invalidate(); - Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); - Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); - // Check if gripper inside the parent (surface), if not we need to move it inside - // This was made for BUG-1682 - if (!imageBounds.Contains(newGripperLocation)) - { - if (newGripperLocation.X > imageBounds.Right) - { - newGripperLocation.X = imageBounds.Right - 5; - } - if (newGripperLocation.X < imageBounds.Left) - { - newGripperLocation.X = imageBounds.Left; - } - if (newGripperLocation.Y > imageBounds.Bottom) - { - newGripperLocation.Y = imageBounds.Bottom - 5; - } - if (newGripperLocation.Y < imageBounds.Top) - { - newGripperLocation.Y = imageBounds.Top; - } - } - - Location = newGripperLocation; - Owner.Invalidate(); - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - targetGraphics.FillRectangle(Brushes.Green, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - } - - /// - /// Made sure this adorner is transformed - /// - /// Matrix - public override void Transform(Matrix matrix) - { - if (matrix == null) - { - return; - } - Point[] points = new[] { Location }; - matrix.TransformPoints(points); - Location = points[0]; - } - } -} diff --git a/Greenshot/Drawing/ArrowContainer.cs b/Greenshot/Drawing/ArrowContainer.cs deleted file mode 100644 index acfd1ad03..000000000 --- a/Greenshot/Drawing/ArrowContainer.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; - -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; - } - } -} diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs deleted file mode 100644 index da160f11e..000000000 --- a/Greenshot/Drawing/CropContainer.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Runtime.Serialization; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; - -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; - } -} diff --git a/Greenshot/Drawing/CursorContainer.cs b/Greenshot/Drawing/CursorContainer.cs deleted file mode 100644 index 7b3078510..000000000 --- a/Greenshot/Drawing/CursorContainer.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.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); - } -} diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs deleted file mode 100644 index bc0973300..000000000 --- a/Greenshot/Drawing/DrawableContainer.cs +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Configuration; -using Greenshot.Drawing.Adorners; -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using Greenshot.Helpers; -using Greenshot.Memento; -using GreenshotPlugin.Interfaces.Drawing; -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 GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.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 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/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs deleted file mode 100644 index a7107543e..000000000 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Configuration; -using Greenshot.Memento; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -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.Forms; -using GreenshotPlugin.Interfaces; - -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; i0) && !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); - } - } - } -} diff --git a/Greenshot/Drawing/EllipseContainer.cs b/Greenshot/Drawing/EllipseContainer.cs deleted file mode 100644 index b7d03ecfe..000000000 --- a/Greenshot/Drawing/EllipseContainer.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; - -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; - } - } -} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs deleted file mode 100644 index 48dfd95f9..000000000 --- a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Runtime.Serialization; - -using Greenshot.Configuration; -using GreenshotPlugin.IniFile; -using log4net; -using GreenshotPlugin.Interfaces.Drawing; - -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); - } - } -} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs deleted file mode 100644 index bb6ae068c..000000000 --- a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Interfaces.Drawing; -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; - -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; - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs deleted file mode 100644 index a1ffd80c1..000000000 --- a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; - -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); - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs deleted file mode 100644 index 5a9652d5c..000000000 --- a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -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. - */ -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(); - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs deleted file mode 100644 index 6a8ff7e84..000000000 --- a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; - -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(); - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs deleted file mode 100644 index d21b575a4..000000000 --- a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -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); - } - -} diff --git a/Greenshot/Drawing/Fields/Field.cs b/Greenshot/Drawing/Fields/Field.cs deleted file mode 100644 index f08033fd0..000000000 --- a/Greenshot/Drawing/Fields/Field.cs +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Interfaces.Drawing; -using System; -using System.ComponentModel; - -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); - } - } -} diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs deleted file mode 100644 index 6606a96b1..000000000 --- a/Greenshot/Drawing/Fields/FieldAggregator.cs +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using Greenshot.Configuration; -using GreenshotPlugin.Interfaces.Drawing; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -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); - } - } - - } -} diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/Greenshot/Drawing/Fields/FieldType.cs deleted file mode 100644 index 7531e5b27..000000000 --- a/Greenshot/Drawing/Fields/FieldType.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using GreenshotPlugin.Interfaces.Drawing; -using System; - -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); - } - } -} diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs deleted file mode 100644 index 631cbed33..000000000 --- a/Greenshot/Drawing/FilterContainer.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using GreenshotPlugin.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); - } - } - } - } -} diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs deleted file mode 100644 index 419038d40..000000000 --- a/Greenshot/Drawing/Filters/AbstractFilter.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; - -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)); - } - } -} diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs deleted file mode 100644 index 79f617ac6..000000000 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -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); - } - } -} diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/Greenshot/Drawing/Filters/BrightnessFilter.cs deleted file mode 100644 index a43a68f67..000000000 --- a/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Imaging; -using System.Drawing.Drawing2D; -using GreenshotPlugin.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); - } - } -} diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/Greenshot/Drawing/Filters/GrayscaleFilter.cs deleted file mode 100644 index f66b29fba..000000000 --- a/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.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); - - } - } -} diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/Greenshot/Drawing/Filters/HighlightFilter.cs deleted file mode 100644 index 38b6a8ee7..000000000 --- a/Greenshot/Drawing/Filters/HighlightFilter.cs +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using GreenshotPlugin.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); - } - } -} diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs deleted file mode 100644 index 68b033ef5..000000000 --- a/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using GreenshotPlugin.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); - } - } -} diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs deleted file mode 100644 index 0485f2ae5..000000000 --- a/Greenshot/Drawing/FreehandContainer.cs +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using GreenshotPlugin.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; - } - } -} diff --git a/Greenshot/Drawing/HighlightContainer.cs b/Greenshot/Drawing/HighlightContainer.cs deleted file mode 100644 index 788360004..000000000 --- a/Greenshot/Drawing/HighlightContainer.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Runtime.Serialization; - -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; - -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; - } - } - } -} diff --git a/Greenshot/Drawing/IconContainer.cs b/Greenshot/Drawing/IconContainer.cs deleted file mode 100644 index 6d5c90986..000000000 --- a/Greenshot/Drawing/IconContainer.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.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); - } -} diff --git a/Greenshot/Drawing/ImageContainer.cs b/Greenshot/Drawing/ImageContainer.cs deleted file mode 100644 index 5840c9507..000000000 --- a/Greenshot/Drawing/ImageContainer.cs +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.Effects; -using GreenshotPlugin.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); - } -} diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs deleted file mode 100644 index 93b76ad89..000000000 --- a/Greenshot/Drawing/LineContainer.cs +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Drawing.Adorners; -using GreenshotPlugin.Interfaces.Drawing; - -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; - } - } -} diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/Greenshot/Drawing/ObfuscateContainer.cs deleted file mode 100644 index f1fdbf156..000000000 --- a/Greenshot/Drawing/ObfuscateContainer.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Runtime.Serialization; -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; - -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; - } - } - } -} diff --git a/Greenshot/Drawing/RectangleContainer.cs b/Greenshot/Drawing/RectangleContainer.cs deleted file mode 100644 index 2e86fa509..000000000 --- a/Greenshot/Drawing/RectangleContainer.cs +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System.Runtime.Serialization; -using GreenshotPlugin.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; - } - } -} diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs deleted file mode 100644 index ee00714e9..000000000 --- a/Greenshot/Drawing/SpeechbubbleContainer.cs +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Text; -using System.Runtime.Serialization; -using GreenshotPlugin.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); - } - } -} diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/Greenshot/Drawing/StepLabelContainer.cs deleted file mode 100644 index b750fcb20..000000000 --- a/Greenshot/Drawing/StepLabelContainer.cs +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Text; -using System.Runtime.Serialization; -using GreenshotPlugin.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); - } - } -} diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs deleted file mode 100644 index ed3118db6..000000000 --- a/Greenshot/Drawing/Surface.cs +++ /dev/null @@ -1,2264 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Configuration; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Memento; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using log4net; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; -using System.Windows.Forms; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.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 - ); - } - } - } -} diff --git a/Greenshot/Forms/AboutForm.cs b/Greenshot/Forms/AboutForm.cs deleted file mode 100644 index f3c67edd8..000000000 --- a/Greenshot/Forms/AboutForm.cs +++ /dev/null @@ -1,333 +0,0 @@ -/* -* Greenshot - a free and open source screenshot tool -* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom -* -* For more information see: http://getgreenshot.org/ -* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 1 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Security.Permissions; -using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using log4net; - -namespace Greenshot.Forms { - /// - /// The about form - /// - public sealed partial class AboutForm : AnimatingBaseForm { - 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 Color _backColor = Color.FromArgb(61, 61, 61); - private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); - - // Variables used for the color-cycle - private int _waitFrames; - private int _colorIndex; - private int _scrollCount; - private bool _hasAnimationsLeft; - - // Variables are used to define the location of the dots - private const int W = 13; - private const int P1 = 7; - private const int P2 = P1 + W; - private const int P3 = P2 + W; - private const int P4 = P3 + W; - private const int P5 = P4 + W; - private const int P6 = P5 + W; - private const int P7 = P6 + W; - - /// - /// The location of every dot in the "G" - /// - private readonly List _gSpots = new List - { - // Top row - new Point(P2, P1), // 0 - new Point(P3, P1), // 1 - new Point(P4, P1), // 2 - new Point(P5, P1), // 3 - new Point(P6, P1), // 4 - - // Second row - new Point(P1, P2), // 5 - new Point(P2, P2), // 6 - - // Third row - new Point(P1, P3), // 7 - new Point(P2, P3), // 8 - - // Fourth row - new Point(P1, P4), // 9 - new Point(P2, P4), // 10 - new Point(P5, P4), // 11 - new Point(P6, P4), // 12 - new Point(P7, P4), // 13 - - // Fifth row - new Point(P1, P5), // 14 - new Point(P2, P5), // 15 - new Point(P6, P5), // 16 - new Point(P7, P5), // 17 - - // Sixth row - new Point(P1, P6), // 18 - new Point(P2, P6), // 19 - new Point(P3, P6), // 20 - new Point(P4, P6), // 21 - new Point(P5, P6), // 22 - new Point(P6, P6) // 23 - }; - - // 0 1 2 3 4 - // 5 6 - // 7 8 - // 9 10 11 12 13 - // 14 15 16 17 - // 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 }; - - /// - /// Cleanup all the allocated resources - /// - private void Cleanup(object sender, EventArgs e) { - if (_bitmap == null) return; - _bitmap.Dispose(); - _bitmap = null; - } - - /// - /// Constructor - /// - public AboutForm() { - // Make sure our resources are removed again. - Disposed += Cleanup; - FormClosing += Cleanup; - - // Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded. - EnableAnimation = true; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - - // Only use double-buffering when we are NOT in a Terminal Server session - DoubleBuffered = !IsTerminalServerSession; - - // Use the self drawn image, first we create the background to be the back-color (as we animate from this) - - _bitmap = ImageHelper.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor, 96, 96); - pictureBox1.Image = _bitmap; - - lblTitle.Text = $@"Greenshot {EnvironmentInfo.GetGreenshotVersion()} {(IniConfig.IsPortable ? " Portable" : "")} ({OsInfo.Bits}) bit)"; - - // Number of frames the pixel animation takes - int frames = FramesForMillis(2000); - // The number of frames the color-cycle waits before it starts - _waitFrames = FramesForMillis(6000); - - // Every pixel is created after pixelWaitFrames frames, which is increased in the loop. - int pixelWaitFrames = FramesForMillis(2000); - // Create pixels - for (int index = 0; index < _gSpots.Count; index++) { - // Read the pixels in the order of the flow - Point gSpot = _gSpots[_flowOrder[index]]; - // Create the animation, first we do nothing (on the final destination) - RectangleAnimator pixelAnimation; - - // Make the pixel grow from the middle, if this offset isn't used it looks like it's shifted - int offset = (W - 2) / 2; - - // If the optimize for Terminal Server is set we make the animation without much ado - 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); - } else { - // Create the animation, first we do nothing (on the final destination) - Rectangle standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); - pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingType.Quintic, EasingMode.EaseIn); - // And than we size to the wanted size. - pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), frames); - } - // Increase the wait frames - pixelWaitFrames += FramesForMillis(100); - // Add to the list of to be animated pixels - _pixels.Add(pixelAnimation); - // Add a color to the list for this pixel. - _pixelColors.Add(_pixelColor); - } - // Make sure the frame "loop" knows we have to animate - _hasAnimationsLeft = true; - - // Pixel Color cycle colors, here we use a pre-animated loop which stores the values. - ColorAnimator pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingType.Quadratic, EasingMode.EaseIn); - pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingType.Quadratic, EasingMode.EaseOut); - do { - _colorFlow.Add(pixelColorAnimator.Current); - pixelColorAnimator.Next(); - } while (pixelColorAnimator.HasNext); - - // color animation for the background - _backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000), EasingType.Linear, EasingMode.EaseIn); - } - - /// - /// This is called when a link is clicked - /// - /// - /// - private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - if (!(sender is LinkLabel linkLabel)) return; - try { - linkLabel.LinkVisited = true; - Process.Start(linkLabel.Text); - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, linkLabel.Text), Language.GetString(LangKey.error)); - } - } - - /// - /// Called from the AnimatingForm, for every frame - /// - protected override void Animate() { - if (_bitmap == null) { - return; - } - if (!IsTerminalServerSession) { - // Color cycle - if (_waitFrames != 0) { - _waitFrames--; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } else if (_scrollCount < _pixelColors.Count + _colorFlow.Count) { - // Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle. - for (int index = _pixelColors.Count - 1; index > 0; index--) { - _pixelColors[index] = _pixelColors[index - 1]; - } - // Keep adding from the colors to cycle until there is nothing left - if (_colorIndex < _colorFlow.Count) { - _pixelColors[0] = _colorFlow[_colorIndex++]; - } - _scrollCount++; - } else { - // Reset values, wait X time for the next one - _waitFrames = FramesForMillis(3000 + _rand.Next(35000)); - _colorIndex = 0; - _scrollCount = 0; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } - } else if (!_hasAnimationsLeft) { - return; - } - - // Draw the "G" - using (Graphics graphics = Graphics.FromImage(_bitmap)) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - graphics.Clear(_backgroundAnimation.Next()); - - graphics.TranslateTransform(2, -2); - graphics.RotateTransform(20); - - using SolidBrush brush = new SolidBrush(_pixelColor); - int index = 0; - // We assume there is nothing to animate in the next Animate loop - _hasAnimationsLeft = false; - // Pixels of the G - foreach (RectangleAnimator pixel in _pixels) { - brush.Color = _pixelColors[index++]; - graphics.FillEllipse(brush, pixel.Current); - // If a pixel still has frames left, the hasAnimationsLeft will be true - _hasAnimationsLeft |= pixel.HasNext; - pixel.Next(); - } - } - pictureBox1.Invalidate(); - } - - /// - /// CmdKey handler - /// - /// - /// - /// - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { - try { - switch (keyData) { - case Keys.Escape: - DialogResult = DialogResult.Cancel; - break; - case Keys.E: - MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); - break; - case Keys.L: - try { - if (File.Exists(MainForm.LogFileLocation)) { - using (Process.Start("\"" + MainForm.LogFileLocation + "\"")) { - // nothing to do, just using dispose to cleanup - } - } else { - MessageBox.Show(@"Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation); - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, @"Error opening greenshot.log", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - case Keys.I: - try { - using (Process.Start("\"" + IniConfig.ConfigLocation + "\"")) { - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.ini, it's located here: " + IniConfig.ConfigLocation, @"Error opening greenshot.ini", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - default: - return base.ProcessCmdKey(ref msg, keyData); - } - } catch (Exception ex) { - Log.Error($"Error handling key '{keyData}'", ex); - } - return true; - } - } -} \ No newline at end of file diff --git a/Greenshot/Forms/BugReportForm.cs b/Greenshot/Forms/BugReportForm.cs deleted file mode 100644 index 7c26e1b54..000000000 --- a/Greenshot/Forms/BugReportForm.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Diagnostics; -using System.Windows.Forms; -using Greenshot.Configuration; -using GreenshotPlugin.Core; - -namespace Greenshot.Forms { - public partial class BugReportForm : BaseForm { - private BugReportForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - ToFront = true; - } - - public BugReportForm(string bugText) : this() { - textBoxDescription.Text = bugText; - } - - private void LinkLblBugsLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - openLink((LinkLabel)sender); - } - - private void openLink(LinkLabel link) { - try { - link.LinkVisited = true; - Process.Start(link.Text); - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, link.Text), Language.GetString(LangKey.error)); - } - } - } -} diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs deleted file mode 100644 index 3cc04ebf6..000000000 --- a/Greenshot/Forms/CaptureForm.cs +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing; -using Greenshot.Helpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; -using log4net; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Globalization; -using System.Security.Permissions; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; - -namespace Greenshot.Forms { - /// - /// The capture form is used to select a part of the capture - /// - public sealed partial class CaptureForm : AnimatingForm { - private enum FixMode {None, Initiated, Horizontal, Vertical}; - - private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureForm)); - private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); - private static readonly Brush GreenOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); - private static readonly Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); - private static CaptureForm _currentForm; - private static readonly Brush BackgroundBrush; - - /// - /// Initialize the background brush - /// - static CaptureForm() { - Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); - BackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); - } - - private int _mX; - private int _mY; - private Point _mouseMovePos = Point.Empty; - private Point _cursorPos; - private CaptureMode _captureMode; - private readonly List _windows; - private WindowDetails _selectedCaptureWindow; - private bool _mouseDown; - private Rectangle _captureRect = Rectangle.Empty; - private readonly ICapture _capture; - private Point _previousMousePos = Point.Empty; - private FixMode _fixMode = FixMode.None; - private RectangleAnimator _windowAnimator; - private RectangleAnimator _zoomAnimator; - private readonly bool _isZoomerTransparent = Conf.ZoomerOpacity < 1; - private bool _isCtrlPressed; - private bool _showDebugInfo; - - /// - /// Property to access the selected capture rectangle - /// - public Rectangle CaptureRectangle => _captureRect; - - /// - /// Property to access the used capture mode - /// - public CaptureMode UsedCaptureMode => _captureMode; - - /// - /// Get the selected window - /// - public WindowDetails SelectedCaptureWindow => _selectedCaptureWindow; - - /// - /// This should prevent children to draw backgrounds - /// - protected override CreateParams CreateParams { - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - get { - CreateParams createParams = base.CreateParams; - createParams.ExStyle |= 0x02000000; - return createParams; - } - } - - private void ClosedHandler(object sender, EventArgs e) { - _currentForm = null; - // Change the final mode - if (_captureMode == CaptureMode.Text) - { - _capture.CaptureDetails.CaptureMode = CaptureMode.Text; - } - Log.Debug("Remove CaptureForm from currentForm"); - } - - private void ClosingHandler(object sender, EventArgs e) { - Log.Debug("Closing capture form"); - WindowDetails.UnregisterIgnoreHandle(Handle); - } - - /// - /// This creates the capture form - /// - /// - /// - public CaptureForm(ICapture capture, List windows) { - if (_currentForm != null) { - Log.Warn("Found currentForm, Closing already opened CaptureForm"); - _currentForm.Close(); - _currentForm = null; - Application.DoEvents(); - } - _currentForm = this; - - // Enable the AnimatingForm - EnableAnimation = true; - - // clean up - FormClosed += ClosedHandler; - - _capture = capture; - _windows = windows; - _captureMode = capture.CaptureDetails.CaptureMode; - - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - // Only double-buffer when we are not in a TerminalServerSession - DoubleBuffered = !IsTerminalServerSession; - Text = @"Greenshot capture form"; - - // Make sure we never capture the capture-form - WindowDetails.RegisterIgnoreHandle(Handle); - // Un-register at close - FormClosing += ClosingHandler; - - // set cursor location - _cursorPos = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - - // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor - if (_captureMode == CaptureMode.Window) { - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - } - - // Set the zoomer animation - InitializeZoomer(Conf.ZoomerEnabled); - - SuspendLayout(); - Bounds = capture.ScreenBounds; - ResumeLayout(); - - // Fix missing focus - ToFront = true; - TopMost = true; - } - - /// - /// Create an animation for the zoomer, depending on if it's active or not. - /// - private void InitializeZoomer(bool isOn) { - 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); - VerifyZoomAnimation(_cursorPos, false); - } - else - { - _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); - } - } - - private void CaptureFormKeyUp(object sender, KeyEventArgs e) { - switch(e.KeyCode) { - case Keys.ShiftKey: - _fixMode = FixMode.None; - break; - case Keys.ControlKey: - _isCtrlPressed = false; - break; - } - } - - /// - /// Handle the key down event - /// - /// - /// - private void CaptureFormKeyDown(object sender, KeyEventArgs e) { - int step = _isCtrlPressed ? 10 : 1; - - switch (e.KeyCode) { - case Keys.Up: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - step); - break; - case Keys.Down: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + step); - break; - case Keys.Left: - Cursor.Position = new Point(Cursor.Position.X - step, Cursor.Position.Y); - break; - case Keys.Right: - Cursor.Position = new Point(Cursor.Position.X + step, Cursor.Position.Y); - break; - case Keys.ShiftKey: - // Fix mode - if (_fixMode == FixMode.None) { - _fixMode = FixMode.Initiated; - } - break; - case Keys.ControlKey: - _isCtrlPressed = true; - break; - case Keys.Escape: - // Cancel - DialogResult = DialogResult.Cancel; - break; - case Keys.M: - // Toggle mouse cursor - _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) { - // Toggle zoom - Conf.ZoomerEnabled = !Conf.ZoomerEnabled; - InitializeZoomer(Conf.ZoomerEnabled); - Invalidate(); - } - break; - case Keys.D: - if (_captureMode == CaptureMode.Window) - { - // Toggle debug - _showDebugInfo = !_showDebugInfo; - Invalidate(); - } - break; - case Keys.Space: - // Toggle capture mode - switch (_captureMode) { - case CaptureMode.Region: - // Set the window capture mode - _captureMode = CaptureMode.Window; - // "Fade out" Zoom - InitializeZoomer(false); - // "Fade in" window - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - case CaptureMode.Text: - // Set the region capture mode - _captureMode = CaptureMode.Region; - Invalidate(); - break; - case CaptureMode.Window: - // Set the region capture mode - _captureMode = CaptureMode.Region; - // "Fade out" window - _windowAnimator.ChangeDestination(new Rectangle(_cursorPos, Size.Empty), FramesForMillis(700)); - // Fade in zoom - InitializeZoomer(Conf.ZoomerEnabled); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - } - _selectedCaptureWindow = null; - OnMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); - break; - case Keys.Return: - // Confirm - if (_captureMode == CaptureMode.Window) { - DialogResult = DialogResult.OK; - } else if (!_mouseDown) { - HandleMouseDown(); - } else if (_mouseDown) { - HandleMouseUp(); - } - break; - case Keys.F: - ToFront = !ToFront; - TopMost = !TopMost; - break; - case Keys.T: - _captureMode = CaptureMode.Text; - if (_capture.CaptureDetails.OcrInformation is null) - { - var ocrProvider = SimpleServiceProvider.Current.GetInstance(); - if (ocrProvider != null) - { - var uiTaskScheduler = SimpleServiceProvider.Current.GetInstance(); - - Task.Factory.StartNew(async () => - { - _capture.CaptureDetails.OcrInformation = await ocrProvider.DoOcrAsync(_capture.Image); - Invalidate(); - }, CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler); - } - } - else - { - Invalidate(); - } - break; - } - } - - /// - /// The mousedown handler of the capture form - /// - /// - /// - private void OnMouseDown(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Left) { - HandleMouseDown(); - } - } - - private void HandleMouseDown() { - Point tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - _mX = tmpCursorLocation.X; - _mY = tmpCursorLocation.Y; - _mouseDown = true; - OnMouseMove(this, null); - Invalidate(); - } - - private void HandleMouseUp() { - // If the mouse goes up we set down to false (nice logic!) - _mouseDown = false; - // Check if anything is selected - if (_captureMode == CaptureMode.Window && _selectedCaptureWindow != null) { - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureRect.Height > 0 && _captureRect.Width > 0) { - // correct the GUI width to real width if Region mode - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - _captureRect.Width += 1; - _captureRect.Height += 1; - } - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureMode == CaptureMode.Text && IsWordUnderCursor(_mouseMovePos)) - { - // Handle a click on a single word - _captureRect = new Rectangle(_mouseMovePos, new Size(1, 1)); - // Go and process the capture - DialogResult = DialogResult.OK; - } else { - Invalidate(); - } - - } - - /// - /// - /// - /// - /// - private bool IsWordUnderCursor(Point cursorLocation) - { - if (_captureMode != CaptureMode.Text || _capture.CaptureDetails.OcrInformation == null) return false; - - var ocrInfo = _capture.CaptureDetails.OcrInformation; - - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - if (lineBounds.IsEmpty) continue; - // Highlight the text which is selected - if (!lineBounds.Contains(cursorLocation)) continue; - foreach (var word in line.Words) - { - if (word.Bounds.Contains(cursorLocation)) - { - return true; - } - } - } - - return false; - } - - /// - /// The mouse up handler of the capture form - /// - /// - /// - private void OnMouseUp(object sender, MouseEventArgs e) { - if (_mouseDown) { - HandleMouseUp(); - } - } - - /// - /// This method is used to "fix" the mouse coordinates when keeping shift/ctrl pressed - /// - /// - /// - private Point FixMouseCoordinates(Point currentMouse) { - if (_fixMode == FixMode.Initiated) { - if (_previousMousePos.X != currentMouse.X) { - _fixMode = FixMode.Vertical; - } else if (_previousMousePos.Y != currentMouse.Y) { - _fixMode = FixMode.Horizontal; - } - } else if (_fixMode == FixMode.Vertical) { - currentMouse = new Point(currentMouse.X, _previousMousePos.Y); - } else if (_fixMode == FixMode.Horizontal) { - currentMouse = new Point(_previousMousePos.X, currentMouse.Y); - } - _previousMousePos = currentMouse; - return currentMouse; - } - - /// - /// The mouse move handler of the capture form - /// - /// object - /// MouseEventArgs - private void OnMouseMove(object sender, MouseEventArgs e) { - // Make sure the mouse coordinates are fixed, when pressing shift - var mouseMovePos = FixMouseCoordinates(User32.GetCursorLocation()); - _mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); - } - - /// - /// Helper method to simplify check - /// - /// - /// - private bool IsAnimating(IAnimator animator) { - if (animator == null) { - return false; - } - return animator.HasNext; - } - - /// - /// update the frame, this only invalidates - /// - protected override void Animate() { - Point lastPos = _cursorPos; - _cursorPos = _mouseMovePos; - - if (_selectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator)) { - return; - } - - WindowDetails lastWindow = _selectedCaptureWindow; - bool horizontalMove = false; - bool verticalMove = false; - - if (lastPos.X != _cursorPos.X) { - horizontalMove = true; - } - if (lastPos.Y != _cursorPos.Y) { - verticalMove = true; - } - - if ((_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) && _mouseDown) { - _captureRect = GuiRectangle.GetGuiRectangle(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y); - } - - // Iterate over the found windows and check if the current location is inside a window - Point cursorPosition = Cursor.Position; - _selectedCaptureWindow = null; - lock (_windows) { - foreach (var window in _windows) { - if (!window.Contains(cursorPosition)) - { - continue; - } - // Only go over the children if we are in window mode - _selectedCaptureWindow = CaptureMode.Window == _captureMode ? window.FindChildUnderPoint(cursorPosition) : window; - break; - } - } - - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; - _capture.CaptureDetails.AddMetaData("windowtitle", _selectedCaptureWindow.Text); - if (_captureMode == CaptureMode.Window) { - // Here we want to capture the window which is under the mouse - _captureRect = _selectedCaptureWindow.WindowRectangle; - // As the ClientRectangle is not in Bitmap coordinates, we need to correct. - _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); - } - } - - Rectangle invalidateRectangle; - if (_mouseDown && (_captureMode != CaptureMode.Window)) { - int x1 = Math.Min(_mX, lastPos.X); - int x2 = Math.Max(_mX, lastPos.X); - int y1 = Math.Min(_mY, lastPos.Y); - int y2 = Math.Max(_mY, lastPos.Y); - x1= Math.Min(x1, _cursorPos.X); - x2= Math.Max(x2, _cursorPos.X); - y1= Math.Min(y1, _cursorPos.Y); - y2= Math.Max(y2, _cursorPos.Y); - - // Safety correction - x2 += 2; - y2 += 2; - - // Here we correct for text-size - - // Calculate the size - int textForWidth = Math.Max(Math.Abs(_mX - _cursorPos.X), Math.Abs(_mX - lastPos.X)); - int textForHeight = Math.Max(Math.Abs(_mY - _cursorPos.Y), Math.Abs(_mY - lastPos.Y)); - - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(textForWidth.ToString(CultureInfo.InvariantCulture), rulerFont); - x1 -= measureWidth.Width + 15; - - Size measureHeight = TextRenderer.MeasureText(textForHeight.ToString(CultureInfo.InvariantCulture), rulerFont); - y1 -= measureHeight.Height + 10; - } - invalidateRectangle = new Rectangle(x1,y1, x2-x1, y2-y1); - Invalidate(invalidateRectangle); - } else if (_captureMode != CaptureMode.Window) { - if (!IsTerminalServerSession) { - Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); - allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); - if (verticalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - } - if (horizontalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - } - } - } else { - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - // Window changes, make new animation from current to target - _windowAnimator.ChangeDestination(_captureRect, FramesForMillis(700)); - } - } - // always animate the Window area through to the last frame, so we see the fade-in/out untill 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 - if (IsAnimating(_windowAnimator)) { - invalidateRectangle = _windowAnimator.Current; - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - invalidateRectangle = _windowAnimator.Next(); - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - // Check if this was the last of the windows animations in the normal region capture. - if (_captureMode != CaptureMode.Window && !IsAnimating(_windowAnimator)) { - Invalidate(); - } - } - - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - // Make sure we invalidate the old zoom area - invalidateRectangle = _zoomAnimator.Current; - invalidateRectangle.Offset(lastPos); - Invalidate(invalidateRectangle); - // Only verify if we are really showing the zoom, not the outgoing animation - if (Conf.ZoomerEnabled && _captureMode != CaptureMode.Window) { - VerifyZoomAnimation(_cursorPos, false); - } - // The following logic is not needed, next always returns the current if there are no frames left - // but it makes more sense if we want to change something in the logic - invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current; - invalidateRectangle.Offset(_cursorPos); - Invalidate(invalidateRectangle); - } - - // OCR - if (_captureMode == CaptureMode.Text && _capture.CaptureDetails.OcrInformation != null) - { - var ocrInfo = _capture.CaptureDetails.OcrInformation; - - invalidateRectangle = Rectangle.Empty; - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - 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)) - { - 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) - { - Invalidate(invalidateRectangle); - } - } - // Force update "now" - Update(); - } - - /// - /// This makes sure there is no background painted, as we have complete "paint" control it doesn't make sense to do otherwise. - /// - /// - protected override void OnPaintBackground(PaintEventArgs pevent) { - } - - /// - /// Checks if the Zoom area can move there where it wants to go, change direction if not. - /// - /// preferred destination location for the zoom area - /// false to try to find a location which is neither out of screen bounds nor intersects with the selected rectangle - private void VerifyZoomAnimation(Point pos, bool allowZoomOverCaptureRect) { - Rectangle screenBounds = Screen.GetBounds(MousePosition); - // convert to be relative to top left corner of all screen bounds - screenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location); - int relativeZoomSize = Math.Min(screenBounds.Width, screenBounds.Height) / 5; - // Make sure the final size is a plural of 4, this makes it look better - relativeZoomSize -= relativeZoomSize % 4; - Size zoomSize = new Size(relativeZoomSize, relativeZoomSize); - Point zoomOffset = new Point(20, 20); - - Rectangle targetRectangle = _zoomAnimator.Final; - targetRectangle.Offset(pos); - 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); - } - if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) { - VerifyZoomAnimation(pos, true); - } else { - _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); - } - } - } - - /// - /// Draw the zoomed area - /// - /// - /// - /// - private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) { - if (_capture.Image == null) { - return; - } - ImageAttributes attributes; - - if (_isZoomerTransparent) { - //create a color matrix object to change the opacy - ColorMatrix opacyMatrix = new ColorMatrix - { - Matrix33 = Conf.ZoomerOpacity - }; - attributes = new ImageAttributes(); - attributes.SetColorMatrix(opacyMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - } else { - attributes = null; - } - - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.HighSpeed; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - using (GraphicsPath path = new GraphicsPath()) { - path.AddEllipse(destinationRectangle); - graphics.SetClip(path); - if (!_isZoomerTransparent) { - graphics.FillRectangle(BackgroundBrush, destinationRectangle); - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); - } else { - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes); - } - } - int alpha = (int)(255 * Conf.ZoomerOpacity); - Color opacyWhite = Color.FromArgb(alpha, 255, 255, 255); - Color opacyBlack = Color.FromArgb(alpha, 0, 0, 0); - - // Draw the circle around the zoomer - using (Pen pen = new Pen(opacyWhite, 2)) { - graphics.DrawEllipse(pen, destinationRectangle); - } - - // Make sure we don't have a pixeloffsetmode/smoothingmode when drawing the crosshair - graphics.SmoothingMode = SmoothingMode.None; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - // Calculate some values - int pixelThickness = destinationRectangle.Width / sourceRectangle.Width; - int halfWidth = destinationRectangle.Width / 2; - int halfWidthEnd = destinationRectangle.Width / 2 - pixelThickness / 2; - int halfHeight = destinationRectangle.Height / 2; - int halfHeightEnd = destinationRectangle.Height / 2 - pixelThickness / 2; - - int drawAtHeight = destinationRectangle.Y + halfHeight; - int drawAtWidth = destinationRectangle.X + halfWidth; - int padding = pixelThickness; - - // Pen to draw - using (Pen pen = new Pen(opacyBlack, pixelThickness)) { - // Draw the cross-hair-lines - // Vertical top to middle - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + padding, drawAtWidth, destinationRectangle.Y + halfHeightEnd - padding); - // Vertical middle + 1 to bottom - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, drawAtWidth, destinationRectangle.Y + destinationRectangle.Width - padding); - // Horizontal left to middle - graphics.DrawLine(pen, destinationRectangle.X + padding, drawAtHeight, destinationRectangle.X + halfWidthEnd - padding, drawAtHeight); - // Horizontal middle + 1 to right - graphics.DrawLine(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, destinationRectangle.X + destinationRectangle.Width - padding, drawAtHeight); - - // Fix offset for drawing the white rectangle around the cross-hair-lines - drawAtHeight -= pixelThickness / 2; - drawAtWidth -= pixelThickness / 2; - // Fix off by one error with the DrawRectangle - pixelThickness -= 1; - // Change the color and the pen width - pen.Color = opacyWhite; - pen.Width = 1; - // Vertical top to middle - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Vertical middle + 1 to bottom - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Horizontal left to middle - graphics.DrawRectangle(pen, destinationRectangle.X + padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - // Horizontal middle + 1 to right - graphics.DrawRectangle(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - } - attributes?.Dispose(); - } - - /// - /// Paint the actual visible parts - /// - /// - /// - private void OnPaint(object sender, PaintEventArgs e) { - Graphics graphics = e.Graphics; - Rectangle clipRectangle = e.ClipRectangle; - //graphics.BitBlt((Bitmap)buffer, Point.Empty); - graphics.DrawImageUnscaled(_capture.Image, Point.Empty); - - var ocrInfo = _capture.CaptureDetails.OcrInformation; - if (ocrInfo != null && _captureMode == CaptureMode.Text) - { - using var pen = new Pen(Color.Red); - var highlightColor = Color.FromArgb(128, Color.Yellow); - using var highlightTextBrush = new SolidBrush(highlightColor); - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - 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)) - { - foreach (var word in line.Words) - { - if (!word.Bounds.Contains(_mouseMovePos)) continue; - graphics.FillRectangle(highlightTextBrush, word.Bounds); - break; - } - } - } - } - } - - // Only draw Cursor if it's (partly) visible - if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) { - graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); - } - - if (_mouseDown || _captureMode == CaptureMode.Window || IsAnimating(_windowAnimator)) { - _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen - - var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect; - - // TODO: enable when the screen capture code works reliable - //if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) { - // graphics.FillRectangle(RedOverlayBrush, fixedRect); - //} else { - graphics.FillRectangle(GreenOverlayBrush, fixedRect); - //} - graphics.DrawRectangle(OverlayPen, fixedRect); - - // rulers - const int dist = 8; - - string captureWidth; - string captureHeight; - // The following fixes the very old incorrect size information bug - if (_captureMode == CaptureMode.Window) { - captureWidth = _captureRect.Width.ToString(CultureInfo.InvariantCulture); - captureHeight = _captureRect.Height.ToString(CultureInfo.InvariantCulture); - } else { - captureWidth = (_captureRect.Width + 1).ToString(CultureInfo.InvariantCulture); - captureHeight = (_captureRect.Height + 1).ToString(CultureInfo.InvariantCulture); - } - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(captureWidth, rulerFont); - Size measureHeight = TextRenderer.MeasureText(captureHeight, rulerFont); - int hSpace = measureWidth.Width + 3; - int vSpace = measureHeight.Height + 3; - Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227)); - Pen rulerPen = new Pen(Color.SeaGreen); - - // horizontal ruler - if (fixedRect.Width > hSpace + 3) - { - using GraphicsPath p = CreateRoundedRectangle( - fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, - fixedRect.Y - dist - 7, - measureWidth.Width - 3, - measureWidth.Height, - 3); - graphics.FillPath(bgBrush, p); - graphics.DrawPath(rulerPen, p); - graphics.DrawString(captureWidth, rulerFont, rulerPen.Brush, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, fixedRect.Y - dist - 7); - graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2), fixedRect.Y - dist); - graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width / 2 + hSpace / 2, fixedRect.Y - dist, fixedRect.X + fixedRect.Width, fixedRect.Y - dist); - graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist - 3, fixedRect.X, fixedRect.Y - dist + 3); - graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width, fixedRect.Y - dist - 3, fixedRect.X + fixedRect.Width, fixedRect.Y - dist + 3); - } - - // vertical ruler - if (fixedRect.Height > vSpace + 3) - { - using GraphicsPath p = CreateRoundedRectangle( - fixedRect.X - measureHeight.Width + 1, - fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, - measureHeight.Width - 3, - measureHeight.Height - 1, - 3); - graphics.FillPath(bgBrush, p); - graphics.DrawPath(rulerPen, p); - graphics.DrawString(captureHeight, rulerFont, rulerPen.Brush, fixedRect.X - measureHeight.Width + 1, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2); - graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y, fixedRect.X - dist, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2)); - graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y + fixedRect.Height / 2 + vSpace / 2, fixedRect.X - dist, fixedRect.Y + fixedRect.Height); - graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y, fixedRect.X - dist + 3, fixedRect.Y); - graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y + fixedRect.Height, fixedRect.X - dist + 3, fixedRect.Y + fixedRect.Height); - } - - rulerPen.Dispose(); - bgBrush.Dispose(); - } - - // Display size of selected rectangle - // Prepare the font and text. - using Font sizeFont = new Font( FontFamily.GenericSansSerif, 12 ); - // When capturing a Region we need to add 1 to the height/width for correction - string sizeText; - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - // correct the GUI width to real width for the shown size - sizeText = _captureRect.Width + 1 + " x " + (_captureRect.Height + 1); - } else { - sizeText = _captureRect.Width + " x " + _captureRect.Height; - } - - // Calculate the scaled font size. - SizeF extent = graphics.MeasureString( sizeText, sizeFont ); - float hRatio = _captureRect.Height / (extent.Height * 2); - float wRatio = _captureRect.Width / (extent.Width * 2); - float ratio = hRatio < wRatio ? hRatio : wRatio; - float newSize = sizeFont.Size * ratio; - - if ( newSize >= 4 ) { - // Only show if 4pt or larger. - if (newSize > 20) { - newSize = 20; - } - // Draw the size. - using Font newSizeFont = new Font(FontFamily.GenericSansSerif, newSize, FontStyle.Bold); - PointF sizeLocation = new PointF(fixedRect.X + _captureRect.Width / 2 - extent.Width / 2, fixedRect.Y + _captureRect.Height / 2 - newSizeFont.GetHeight() / 2); - graphics.DrawString(sizeText, newSizeFont, Brushes.LightSeaGreen, sizeLocation); - - if (_showDebugInfo && _selectedCaptureWindow != null) - { - string title = $"#{_selectedCaptureWindow.Handle.ToInt64():X} - {(_selectedCaptureWindow.Text.Length > 0 ? _selectedCaptureWindow.Text : _selectedCaptureWindow.Process.ProcessName)}"; - PointF debugLocation = new PointF(fixedRect.X, fixedRect.Y); - graphics.DrawString(title, sizeFont, Brushes.DarkOrange, debugLocation); - } - } - } else { - if (!IsTerminalServerSession) { - using (Pen pen = new Pen(Color.LightSeaGreen)) { - pen.DashStyle = DashStyle.Dot; - Rectangle screenBounds = _capture.ScreenBounds; - graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height); - graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y); - } - - string xy = _cursorPos.X + " x " + _cursorPos.Y; - using Font f = new Font(FontFamily.GenericSansSerif, 8); - Size xySize = TextRenderer.MeasureText(xy, f); - using GraphicsPath gp = CreateRoundedRectangle(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3); - using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) { - graphics.FillPath(bgBrush, gp); - } - using (Pen pen = new Pen(Color.SeaGreen)) { - graphics.DrawPath(pen, gp); - Point coordinatePosition = new Point(_cursorPos.X + 5, _cursorPos.Y + 5); - graphics.DrawString(xy, f, pen.Brush, coordinatePosition); - } - } - } - - // Zoom - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - const int zoomSourceWidth = 25; - const int zoomSourceHeight = 25; - - Rectangle sourceRectangle = new Rectangle(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); - - Rectangle destinationRectangle = _zoomAnimator.Current; - destinationRectangle.Offset(_cursorPos); - DrawZoom(graphics, sourceRectangle, destinationRectangle); - } - } - - private static GraphicsPath CreateRoundedRectangle(int x, int y, int width, int height, int radius) - { - var gp = new GraphicsPath(); - gp.AddLine(x + radius, y, x + width - radius * 2, y); // Line - gp.AddArc(x + width - radius * 2, y, radius * 2, radius * 2, 270, 90); // Corner - gp.AddLine(x + width, y + radius, x + width, y + height - radius * 2); // Line - gp.AddArc(x + width - radius * 2, y + height - radius * 2, radius * 2, radius * 2, 0, 90); // Corner - gp.AddLine(x + width - radius * 2, y + height, x + radius, y + height); // Line - gp.AddArc(x, y + height - radius * 2, radius * 2, radius * 2, 90, 90); // Corner - gp.AddLine(x, y + height - radius * 2, x, y + radius); // Line - gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner - gp.CloseFigure(); - - return gp; - } - } -} diff --git a/Greenshot/Forms/ColorDialog.cs b/Greenshot/Forms/ColorDialog.cs deleted file mode 100644 index b93c01258..000000000 --- a/Greenshot/Forms/ColorDialog.cs +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.Threading; -using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Controls; -using GreenshotPlugin.IniFile; - -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