commit a22b7578bde5677cf06392cf3cfcfb66019b6373 Author: JKlingen Date: Sun Jul 25 08:48:59 2010 +0000 moved all sources to trunk directory git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@693 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4 diff --git a/Greenshot-OCR-Plugin/Greenshot-OCR-Plugin.csproj b/Greenshot-OCR-Plugin/Greenshot-OCR-Plugin.csproj new file mode 100644 index 000000000..9a22173b5 --- /dev/null +++ b/Greenshot-OCR-Plugin/Greenshot-OCR-Plugin.csproj @@ -0,0 +1,94 @@ + + + {C6988EE8-2FEE-4349-9F09-F9628A0D8965} + Debug + x86 + Library + GreenshotOCR + Greenshot-OCR-Plugin + v2.0 + Properties + C:\Dokumente und Einstellungen\05018085\Anwendungsdaten\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis + False + False + 4 + false + OnBuildSuccess + + + x86 + False + Auto + 4194304 + 4096 + + + bin\Debug\ + true + Full + False + True + DEBUG;TRACE + + + bin\Release\ + False + None + True + False + TRACE + + + + + ..\Greenshot\Lib\log4net.dll + + + lib\MODI11.dll + + + lib\MODI12.dll + + + + + + + + + + + + + SettingsForm.cs + + + Always + + + Always + + + Always + + + + + + + + {5B924697-4DCD-4F98-85F1-105CB84B7341} + GreenshotPlugin + + + + + + "$(SolutionDir)\tools\TortoiseSVN\SubWCRev.exe" "$(ProjectDir)\" "$(ProjectDir)\Properties\AssemblyInfo.cs.template" "$(ProjectDir)\Properties\AssemblyInfo.cs" + mkdir "$(SolutionDir)bin\$(Configuration)\Plugins\$(ProjectName)" +copy "$(ProjectDir)bin\$(Configuration)\$(TargetFileName)" "$(SolutionDir)bin\$(Configuration)\Plugins\$(ProjectName)\*.gsp" +copy "$(ProjectDir)bin\$(Configuration)\MODI*.dll" "$(SolutionDir)bin\$(Configuration)\Plugins\$(ProjectName)\*" +mkdir "$(SolutionDir)bin\$(Configuration)\Languages\Plugins\$(ProjectName)" +copy "$(ProjectDir)bin\$(Configuration)\Languages\*.xml" "$(SolutionDir)bin\$(Configuration)\Languages\Plugins\$(ProjectName)\" + + \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/Language.cs b/Greenshot-OCR-Plugin/Language.cs new file mode 100644 index 000000000..90788ff70 --- /dev/null +++ b/Greenshot-OCR-Plugin/Language.cs @@ -0,0 +1,47 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Diagnostics; +using System.Globalization; +using System.Resources; +using System.Threading; + +using GreenshotPlugin.Core; + +namespace GreenshotOCR { + /// + /// Wrapper for the language container for the Jira plugin. + /// + public class Language : LanguageContainer, ILanguage { + private static ILanguage uniqueInstance; + private const string LANGUAGE_FILENAME_PATTERN = @"language_ocrplugin-*.xml"; + + public static ILanguage GetInstance() { + if(uniqueInstance == null) { + uniqueInstance = new LanguageContainer(); + uniqueInstance.LanguageFilePattern = LANGUAGE_FILENAME_PATTERN; + uniqueInstance.Load(); + uniqueInstance.SetLanguage(Thread.CurrentThread.CurrentUICulture.Name); + } + return uniqueInstance; + } + } +} diff --git a/Greenshot-OCR-Plugin/LanguageKeys.cs b/Greenshot-OCR-Plugin/LanguageKeys.cs new file mode 100644 index 000000000..608cd638a --- /dev/null +++ b/Greenshot-OCR-Plugin/LanguageKeys.cs @@ -0,0 +1,29 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +namespace GreenshotOCR { + public enum LangKey { + language, + orient_image, + straighten_image + } +} diff --git a/Greenshot-OCR-Plugin/Languages/language_ocrplugin-de-DE.xml b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-de-DE.xml new file mode 100644 index 000000000..1cf74afca --- /dev/null +++ b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-de-DE.xml @@ -0,0 +1,14 @@ + + + + + Sprache für OCR + + + Bild Orientieren + + + Bild Aufrichten + + + \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/Languages/language_ocrplugin-en-US.xml b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-en-US.xml new file mode 100644 index 000000000..9bdb7fda1 --- /dev/null +++ b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-en-US.xml @@ -0,0 +1,14 @@ + + + + + Language for OCR + + + Orient image + + + Straighten image + + + \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/Languages/language_ocrplugin-nl-NL.xml b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-nl-NL.xml new file mode 100644 index 000000000..c60f48524 --- /dev/null +++ b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-nl-NL.xml @@ -0,0 +1,14 @@ + + + + + Taal voor OCR + + + Beeld richten + + + Beeld vereffenen + + + \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/OCRPlugin.cs b/Greenshot-OCR-Plugin/OCRPlugin.cs new file mode 100644 index 000000000..8917ed043 --- /dev/null +++ b/Greenshot-OCR-Plugin/OCRPlugin.cs @@ -0,0 +1,322 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Windows.Forms; + +using Greenshot.Plugin; +using GreenshotPlugin.Core; +using Microsoft.Win32; + +namespace GreenshotOCR { + /// + /// OCR Plugin Greenshot + /// + public class OcrPlugin : IGreenshotPlugin { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OcrPlugin)); + private const string CONFIG_FILENAME = "ocr-config.properties"; + + private const string MODI_OFFICE11 = @"Software\Microsoft\Office\11.0\MODI"; + private const string MODI_OFFICE12 = @"Software\Microsoft\Office\12.0\MODI"; + + private IGreenshotPluginHost host; + private ICaptureHost captureHost = null; + private PluginAttribute myAttributes; + private Properties config = new Properties(); + + public OcrPlugin() { } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// Use the IGreenshotPluginHost interface to register events + /// Use the ICaptureHost interface to register in the MainContextMenu + /// My own attributes + public void Initialize(IGreenshotPluginHost host, ICaptureHost captureHost, PluginAttribute myAttributes) { + LOG.Debug("Initialize called of " + myAttributes.Name); + this.host = (IGreenshotPluginHost)host; + this.captureHost = captureHost; + this.myAttributes = myAttributes; + + // Make sure the MODI-DLLs are found by adding a resolver + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyAssemblyResolver); + + if (!HasMODI()) { + LOG.Warn("No MODI found!"); + return; + } + LoadConfig(); + this.host.RegisterHotKey(3, 0x2C, new HotKeyHandler(MyHotkeyHandler)); + + // Here we can hang ourselves to the main context menu! + ToolStripMenuItem item = new ToolStripMenuItem(); + item.Text = "Region OCR"; + item.ShortcutKeyDisplayString = "Ctrl + Alt + Print"; + item.Click += new System.EventHandler(MainMenuClick); + + ContextMenuStrip contextMenu = host.MainMenu; + bool addedItem = false; + + for(int i=0; i < contextMenu.Items.Count; i++) { + if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) { + contextMenu.Items.Insert(i, item); + addedItem = true; + break; + } + } + if (!addedItem) { + contextMenu.Items.Add(item); + } + } + + /// + /// Implementation of the IGreenshotPlugin.Shutdown + /// + public void Shutdown() { + LOG.Debug("Shutdown of " + myAttributes.Name); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public virtual void Configure() { + if (!HasMODI()) { + MessageBox.Show("Sorry, is seems that Microsoft Office Document Imaging (MODI) is not installed, therefor the OCR Plugin cannot work."); + return; + } + SettingsForm settingsForm = new SettingsForm(GetLanguages(),config); + DialogResult result = settingsForm.ShowDialog(); + if (result == DialogResult.OK) { + config.ChangeProperty("language", settingsForm.OCRLanguage); + config.ChangeBoolProperty("orientImage", settingsForm.OrientImage); + config.ChangeBoolProperty("straightenImage", settingsForm.StraightenImage);; + SaveConfig(); + } + } + + /// + /// This method helps to resolve the MODI DLL files + /// + /// object which is starting the resolve + /// ResolveEventArgs describing the Assembly that needs to be found + /// + private Assembly MyAssemblyResolver(object sender, ResolveEventArgs args) { + string dllPath = Path.GetDirectoryName(myAttributes.DllFile); + string dllFilename = args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll"; + LOG.Debug("Resolving: " + dllFilename); + if (dllFilename.StartsWith("MODI")) { + return Assembly.LoadFile(Path.Combine(dllPath, dllFilename)); + } + return null; + } + + private void LoadConfig() { + string filename = Path.Combine(host.ConfigurationPath, CONFIG_FILENAME); + if (File.Exists(filename)) { + LOG.Debug("Loading configuration from: " + filename); + config = Properties.read(filename); + } + bool changed = false; + if (config == null) { + config = new Properties(); + changed = true; + } + if (!config.ContainsKey("language")) { + config.AddProperty("language", "miLANG_ENGLISH"); + changed = true; + } + if (!config.ContainsKey("straightenImage")) { + config.AddBoolProperty("straightenImage", false); + changed = true; + } + if (!config.ContainsKey("orientImage")) { + config.AddBoolProperty("orientImage", false); + changed = true; + } + if (changed) { + SaveConfig(); + } + + } + + private void SaveConfig() { + string filename = Path.Combine(host.ConfigurationPath, CONFIG_FILENAME); + LOG.Debug("Saving configuration to: " + filename); + config.write(filename, "# The configuration file for the Greenshot OCR Plugin"); + } + + private void StartOCRRegion() { + LOG.Debug("Starting OCR!"); + captureHost.MakeCapture(CaptureMode.Region, false, new CaptureHandler(DoOCR)); + } + + private void MyHotkeyHandler() { + StartOCRRegion(); + } + /// + /// Is called when the OCR menu is selected + /// + /// ContextMenu + /// EventArgs from ContextMenu + private void MainMenuClick(object sender, EventArgs e) { + StartOCRRegion(); + } + + /// + /// Handling of the CaptureTaken "event" from the ICaptureHost + /// We do the OCR here! + /// + /// Has the Image and the capture details + private const int MIN_WIDTH = 130; + private const int MIN_HEIGHT = 130; + private void DoOCR(object sender, CaptureTakenEventArgs eventArgs) { + if (eventArgs.Capture.Image == null) { + return; + } + string file = host.GetFilename("bmp", eventArgs.Capture.CaptureDetails); + string filePath = Path.Combine(Path.GetTempPath(),file); + + using (FileStream stream = File.Create(filePath)) { + Image capturedImage = eventArgs.Capture.Image; + if (capturedImage.Width < MIN_WIDTH || capturedImage.Height < MIN_HEIGHT) { + LOG.Debug("Image not big enough, copying to bigger image"); + int newWidth = Math.Max(capturedImage.Width, MIN_WIDTH); + int newHeight = Math.Max(capturedImage.Height, MIN_HEIGHT); + using (Image tmpImage = new Bitmap(newWidth, newHeight, capturedImage.PixelFormat)) { + using (Graphics graphics = Graphics.FromImage(tmpImage)) { + graphics.Clear(Color.White); + graphics.DrawImage(capturedImage, Point.Empty); + } + host.SaveToStream(tmpImage, stream, "bmp", 100); + } + } else { + host.SaveToStream(capturedImage, stream, "bmp", 100); + } + } + + LOG.Debug("Saved tmp file to: " + filePath); + + string text = ""; + + try { + + switch (CheckModiVersion()) { + case ModiVersion.MODI11: + // Instantiate the MODI.Document object + MODI11.Document modi11Document = new MODI11.Document(); + // The Create method grabs the picture from disk snd prepares for OCR. + modi11Document.Create(filePath); + + // Add progress bar here: + //md.OnOCRProgress += ; + + // Do the OCR. + modi11Document.OCR((MODI11.MiLANGUAGES)Enum.Parse(typeof(MODI11.MiLANGUAGES), config.GetProperty("language")), config.GetBoolProperty("orientImage"), config.GetBoolProperty("straightenImage")); + // Get the first (and only image) + MODI11.Image modi11Image = (MODI11.Image)modi11Document.Images[0]; + // Get the layout. + MODI11.Layout modi11layout = modi11Image.Layout; + text = modi11layout.Text; + // Close the MODI.Document object. + modi11Document.Close(false); + break; + case ModiVersion.MODI12: + // Instantiate the MODI.Document object + MODI12.Document modi12Document = new MODI12.Document(); + // The Create method grabs the picture from disk snd prepares for OCR. + modi12Document.Create(filePath); + + // Add progress bar here: + //md.OnOCRProgress += ; + + // Do the OCR. + modi12Document.OCR((MODI12.MiLANGUAGES)Enum.Parse(typeof(MODI12.MiLANGUAGES), config.GetProperty("language")), config.GetBoolProperty("orientImage"), config.GetBoolProperty("straightenImage")); + // Get the first (and only image) + MODI12.Image modi12Image = (MODI12.Image)modi12Document.Images[0]; + // Get the layout. + MODI12.Layout modi12layout = modi12Image.Layout; + text = modi12layout.Text; + // Close the MODI.Document object. + modi12Document.Close(false); + break; + default: + LOG.Error("Unknown MODI version!"); + break; + } + + // Paste to Clipboard (the Plugin currently doesn't have access to the ClipboardHelper from Greenshot + IDataObject ido = new DataObject(); + ido.SetData(DataFormats.Text, true, text); + Clipboard.SetDataObject(ido, true); + } catch (Exception e) { + string message = "A problem occured while trying to OCR the region, this plugin is still in a experimental stage!!"; + LOG.Error(message, e); + MessageBox.Show(message); + } finally { + if (File.Exists(filePath)) { + LOG.Debug("Cleaning up tmp file: " + filePath); + File.Delete(filePath); + } + } + } + + private string [] GetLanguages() { + string [] languages = null; + switch (CheckModiVersion()) { + case ModiVersion.MODI11: + languages = Enum.GetNames(typeof(MODI11.MiLANGUAGES)); + break; + case ModiVersion.MODI12: + languages =Enum.GetNames(typeof(MODI12.MiLANGUAGES)); + break; + } + return languages; + } + + private enum ModiVersion { None, MODI11, MODI12 }; + + private ModiVersion CheckModiVersion() { + using (RegistryKey key = Registry.CurrentUser.OpenSubKey(MODI_OFFICE11, false)) { + if (key != null) { + LOG.Debug("Found Modi V11 in registry: " + key.Name); + return ModiVersion.MODI11; + } + } + using (RegistryKey key = Registry.CurrentUser.OpenSubKey(MODI_OFFICE12, false)) { + if (key != null) { + LOG.Debug("Found Modi V12 in registry: " + key.Name); + return ModiVersion.MODI12; + } + } + return ModiVersion.None; + } + + private bool HasMODI() { + return CheckModiVersion() != ModiVersion.None; + } + } +} \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/Properties/AssemblyInfo.cs.template b/Greenshot-OCR-Plugin/Properties/AssemblyInfo.cs.template new file mode 100644 index 000000000..2e833d825 --- /dev/null +++ b/Greenshot-OCR-Plugin/Properties/AssemblyInfo.cs.template @@ -0,0 +1,54 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +#region Using directives + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Plugin; + +#endregion + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GreenshotOCR")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GreenshotOCR")] +[assembly: AssemblyCopyright("Copyright 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +// The PluginAttribute describes the "entryType" and if the plugin is configurable +[assembly: PluginAttribute("GreenshotOCR.OcrPlugin", true)] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all the values or you can use the default the Revision and +// Build Numbers by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.$WCREV$")] diff --git a/Greenshot-OCR-Plugin/SettingsForm.Designer.cs b/Greenshot-OCR-Plugin/SettingsForm.Designer.cs new file mode 100644 index 000000000..005b98d3a --- /dev/null +++ b/Greenshot-OCR-Plugin/SettingsForm.Designer.cs @@ -0,0 +1,138 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +namespace GreenshotOCR +{ + partial class SettingsForm + { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.comboBox_languages = new System.Windows.Forms.ComboBox(); + this.checkBox_orientImage = new System.Windows.Forms.CheckBox(); + this.checkBox_straightenImage = new System.Windows.Forms.CheckBox(); + this.label_language = new System.Windows.Forms.Label(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // comboBox_languages + // + this.comboBox_languages.FormattingEnabled = true; + this.comboBox_languages.Items.AddRange(new object[] { + "English", + "Deutsch"}); + this.comboBox_languages.Location = new System.Drawing.Point(74, 12); + this.comboBox_languages.Name = "comboBox_languages"; + this.comboBox_languages.Size = new System.Drawing.Size(153, 21); + this.comboBox_languages.TabIndex = 0; + // + // checkBox_orientImage + // + this.checkBox_orientImage.Location = new System.Drawing.Point(13, 41); + this.checkBox_orientImage.Name = "checkBox_orientImage"; + this.checkBox_orientImage.Size = new System.Drawing.Size(104, 24); + this.checkBox_orientImage.TabIndex = 1; + this.checkBox_orientImage.Text = "Orient image"; + this.checkBox_orientImage.UseVisualStyleBackColor = true; + // + // checkBox_straightenImage + // + this.checkBox_straightenImage.Location = new System.Drawing.Point(123, 41); + this.checkBox_straightenImage.Name = "checkBox_straightenImage"; + this.checkBox_straightenImage.Size = new System.Drawing.Size(109, 24); + this.checkBox_straightenImage.TabIndex = 2; + this.checkBox_straightenImage.Text = "Straighten image"; + this.checkBox_straightenImage.UseVisualStyleBackColor = true; + // + // label_language + // + this.label_language.Location = new System.Drawing.Point(13, 15); + this.label_language.Name = "label_language"; + this.label_language.Size = new System.Drawing.Size(55, 23); + this.label_language.TabIndex = 3; + this.label_language.Text = "Language"; + // + // buttonOK + // + this.buttonOK.Location = new System.Drawing.Point(13, 72); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(104, 23); + this.buttonOK.TabIndex = 4; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.ButtonOKClick); + // + // buttonCancel + // + this.buttonCancel.Location = new System.Drawing.Point(123, 72); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(104, 23); + this.buttonCancel.TabIndex = 5; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.ButtonCancelClick); + // + // SettingsForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(244, 111); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.label_language); + this.Controls.Add(this.checkBox_straightenImage); + this.Controls.Add(this.checkBox_orientImage); + this.Controls.Add(this.comboBox_languages); + this.Name = "SettingsForm"; + this.Text = "SettingsForm"; + this.ResumeLayout(false); + } + private System.Windows.Forms.Label label_language; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.CheckBox checkBox_orientImage; + private System.Windows.Forms.CheckBox checkBox_straightenImage; + private System.Windows.Forms.ComboBox comboBox_languages; + } +} diff --git a/Greenshot-OCR-Plugin/SettingsForm.cs b/Greenshot-OCR-Plugin/SettingsForm.cs new file mode 100644 index 000000000..5b481c21e --- /dev/null +++ b/Greenshot-OCR-Plugin/SettingsForm.cs @@ -0,0 +1,99 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +using GreenshotPlugin.Core; + +namespace GreenshotOCR { + /// + /// Description of SettingsForm. + /// + public partial class SettingsForm : Form { + private ILanguage language = Language.GetInstance(); + private string selectedLanguage; + private bool orientImage; + private bool straightenImage; + + public SettingsForm(string [] languages, Properties config) { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + language.SynchronizeLanguageToCulture(); + initializeComponentText(); + + comboBox_languages.Items.Clear(); + int index=0; + foreach(string availableLanguage in languages) { + string displayLanguage = cleanLanguage(availableLanguage); + comboBox_languages.Items.Add(displayLanguage); + if (availableLanguage.Equals(config["language"])) { + comboBox_languages.SelectedIndex = index; + } + index++; + } + checkBox_orientImage.Checked = config.GetBoolProperty("orientImage"); + checkBox_straightenImage.Checked = config.GetBoolProperty("straightenImage"); + } + private void initializeComponentText() { + this.label_language.Text = language.GetString(LangKey.language); + this.checkBox_orientImage.Text = language.GetString(LangKey.orient_image); + } + + private string cleanLanguage(string suppliedLanguage) { + string displayLanguage = ""; + if (suppliedLanguage != null) { + displayLanguage = suppliedLanguage.Replace("miLANG_","").Replace("_"," "); + displayLanguage = displayLanguage.Substring(0, 1).ToUpper() + displayLanguage.Substring(1).ToLower(); + } + return displayLanguage; + } + + public string OCRLanguage { + get {return selectedLanguage;} + } + public bool OrientImage { + get {return orientImage;} + } + public bool StraightenImage { + get {return straightenImage;} + } + + void ButtonCancelClick(object sender, EventArgs e) { + DialogResult = DialogResult.Cancel; + } + + void ButtonOKClick(object sender, EventArgs e) { + string selectedString = (string) comboBox_languages.SelectedItem; + if (selectedString != null) { + selectedLanguage = "miLANG_" + selectedString.ToUpper().Replace(" ", "_"); + } + orientImage = checkBox_orientImage.Checked; + straightenImage = checkBox_straightenImage.Checked; + + DialogResult = DialogResult.OK; + + } + } +} diff --git a/Greenshot-OCR-Plugin/lib/GEN.BAT b/Greenshot-OCR-Plugin/lib/GEN.BAT new file mode 100644 index 000000000..9d6898394 --- /dev/null +++ b/Greenshot-OCR-Plugin/lib/GEN.BAT @@ -0,0 +1,2 @@ +tlbimp Office12\MDIVWCTL.DLL /namespace:MODI12 /out:MODI12.dll +tlbimp Office11\MDIVWCTL.DLL /namespace:MODI11 /out:MODI11.dll \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/lib/MODI11.dll b/Greenshot-OCR-Plugin/lib/MODI11.dll new file mode 100644 index 000000000..ce731f965 Binary files /dev/null and b/Greenshot-OCR-Plugin/lib/MODI11.dll differ diff --git a/Greenshot-OCR-Plugin/lib/MODI12.dll b/Greenshot-OCR-Plugin/lib/MODI12.dll new file mode 100644 index 000000000..ce03e65a3 Binary files /dev/null and b/Greenshot-OCR-Plugin/lib/MODI12.dll differ diff --git a/Greenshot-OCR-Plugin/lib/Office11/MDIVWCTL.DLL b/Greenshot-OCR-Plugin/lib/Office11/MDIVWCTL.DLL new file mode 100644 index 000000000..477b6076e Binary files /dev/null and b/Greenshot-OCR-Plugin/lib/Office11/MDIVWCTL.DLL differ diff --git a/Greenshot-OCR-Plugin/lib/Office12/MDIVWCTL.DLL b/Greenshot-OCR-Plugin/lib/Office12/MDIVWCTL.DLL new file mode 100644 index 000000000..47384168f Binary files /dev/null and b/Greenshot-OCR-Plugin/lib/Office12/MDIVWCTL.DLL differ diff --git a/Greenshot-RunAtOutput-Plugin/Configuration.cs b/Greenshot-RunAtOutput-Plugin/Configuration.cs new file mode 100644 index 000000000..2919f8872 --- /dev/null +++ b/Greenshot-RunAtOutput-Plugin/Configuration.cs @@ -0,0 +1,66 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Xml; +using System.Xml.Serialization; + +namespace RunAtOutput { + /// + /// Description of Configuration. + /// + [XmlRoot("RunAtOutput")] + public class Configuration { + public Configuration() { + Commands = new List(); + } + [XmlElement("Commando")] + public List Commands { + get; + set; + } + } + + public class Commando { + public Commando() { + } + [XmlAttribute("Name")] + public string Name { + get; + set; + } + [XmlElement("Commandline")] + public string Commandline { + get; + set; + } + [XmlElement("Arguments")] + public string Arguments { + get; + set; + } + [XmlAttribute("Active")] + public bool Active{ + get; + set; + } + } +} diff --git a/Greenshot-RunAtOutput-Plugin/Greenshot-RunAtOutput-Plugin.csproj b/Greenshot-RunAtOutput-Plugin/Greenshot-RunAtOutput-Plugin.csproj new file mode 100644 index 000000000..03bfc7759 --- /dev/null +++ b/Greenshot-RunAtOutput-Plugin/Greenshot-RunAtOutput-Plugin.csproj @@ -0,0 +1,73 @@ + + + {47F23C86-604E-4CC3-8767-B3D4088F30BB} + Debug + x86 + Library + Greenshot_RunAtOutput_Plugin + Greenshot-RunAtOutput-Plugin + v2.0 + Properties + C:\Users\Robin\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis + False + False + 4 + false + OnBuildSuccess + + + x86 + False + Auto + 4194304 + 4096 + + + bin\Debug\ + true + Full + False + True + DEBUG;TRACE + + + bin\Release\ + False + None + True + False + TRACE + + + + + ..\Greenshot\Lib\log4net.dll + + + + + + + + + + + + + SettingsForm.cs + + + + + + "$(SolutionDir)\tools\TortoiseSVN\SubWCRev.exe" "$(ProjectDir)\" "$(ProjectDir)\Properties\AssemblyInfo.cs.template" "$(ProjectDir)\Properties\AssemblyInfo.cs" + mkdir "$(SolutionDir)bin\$(Configuration)\Plugins\$(ProjectName)" +copy "$(ProjectDir)bin\$(Configuration)\$(TargetFileName)" "$(SolutionDir)bin\$(Configuration)\Plugins\$(ProjectName)\*.gsp" + + + + {5B924697-4DCD-4F98-85F1-105CB84B7341} + GreenshotPlugin + + + \ No newline at end of file diff --git a/Greenshot-RunAtOutput-Plugin/Properties/AssemblyInfo.cs.template b/Greenshot-RunAtOutput-Plugin/Properties/AssemblyInfo.cs.template new file mode 100644 index 000000000..a088e1b28 --- /dev/null +++ b/Greenshot-RunAtOutput-Plugin/Properties/AssemblyInfo.cs.template @@ -0,0 +1,53 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +#region Using directives + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Plugin; + +#endregion + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Greenshot-RunAtOutput-Plugin")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Greenshot-RunAtOutput-Plugin")] +[assembly: AssemblyCopyright("Copyright 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: PluginAttribute("RunAtOutput.RunAtOutputPlugin", true)] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all the values or you can use the default the Revision and +// Build Numbers by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.$WCREV$")] diff --git a/Greenshot-RunAtOutput-Plugin/RunAtOutput.cs b/Greenshot-RunAtOutput-Plugin/RunAtOutput.cs new file mode 100644 index 000000000..e0b1e9c07 --- /dev/null +++ b/Greenshot-RunAtOutput-Plugin/RunAtOutput.cs @@ -0,0 +1,125 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Text; +using System.Windows.Forms; +using System.Xml.Serialization; + +using Greenshot.Plugin; + +namespace RunAtOutput { + /// + /// An Plugin to run commands after an image was written + /// + public class RunAtOutputPlugin : IGreenshotPlugin { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(RunAtOutputPlugin)); + private IGreenshotPluginHost host; + private ICaptureHost captureHost = null; + private PluginAttribute myAttributes; + private Configuration config = new Configuration(); + + public RunAtOutputPlugin() { + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// Use the IGreenshotPluginHost interface to register events + /// Use the ICaptureHost interface to register in the MainContextMenu + /// My own attributes + public virtual void Initialize(IGreenshotPluginHost pluginHost, ICaptureHost captureHost, PluginAttribute myAttributes) { + LOG.Debug("Initialize called of " + myAttributes.Name); + + this.host = (IGreenshotPluginHost)pluginHost; + this.captureHost = captureHost; + this.myAttributes = myAttributes; + this.host.OnImageOutput += new OnImageOutputHandler(ImageOutput); + + LoadConfig(); + } + + public virtual void Shutdown() { + LOG.Debug("Shutdown of " + myAttributes.Name); + this.host.OnImageOutput -= new OnImageOutputHandler(ImageOutput); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public virtual void Configure() { + LOG.Debug("Configure called"); + SettingsForm settingsForm = new SettingsForm(config); + if (settingsForm.ShowDialog() == DialogResult.OK) { + SaveConfig(); + } + settingsForm.Dispose(); + } + + private void LoadConfig() { + XmlSerializer xmlSerializer = new XmlSerializer(typeof(Configuration)); + string filename = Path.Combine(host.ConfigurationPath, "RunAtOutputPlugin.xml"); + if (File.Exists(filename)) { + using (TextReader reader = new StreamReader(filename)) { + config = (Configuration)xmlSerializer.Deserialize(reader); + } + } + } + + private void SaveConfig() { + XmlSerializer xmlSerializer = new XmlSerializer(typeof(Configuration)); + string filename = Path.Combine(host.ConfigurationPath, "RunAtOutputPlugin.xml"); + using (TextWriter writer = new StreamWriter(filename)) { + xmlSerializer.Serialize(writer, config); + } + } + + /// + /// Handling of the OnImageOutputHandler event from the IGreenshotPlugin + /// + /// Has the FullPath to the image + private void ImageOutput(object sender, ImageOutputEventArgs eventArgs) { + LOG.Debug("ImageOutput called with full path: " + eventArgs.FullPath); + foreach(Commando commando in config.Commands) { + if (commando.Active) { + if (commando.Commandline != null && commando.Commandline.Length > 0) { + Process p = new Process(); + p.StartInfo.FileName = commando.Commandline; + p.StartInfo.Arguments = String.Format(commando.Arguments, eventArgs.FullPath); + p.StartInfo.UseShellExecute = false; + p.StartInfo.RedirectStandardOutput = true; + LOG.Info("Starting : " + p.StartInfo.FileName + " " + p.StartInfo.Arguments); + p.Start(); + string output = p.StandardOutput.ReadToEnd(); + if (output != null && output.Trim().Length > 0) { + LOG.Info("Output:\n" + output); + } + LOG.Info("Finished : " + p.StartInfo.FileName + " " + p.StartInfo.Arguments); + } + } + } + } + } +} \ No newline at end of file diff --git a/Greenshot-RunAtOutput-Plugin/SettingsForm.Designer.cs b/Greenshot-RunAtOutput-Plugin/SettingsForm.Designer.cs new file mode 100644 index 000000000..f3bde520e --- /dev/null +++ b/Greenshot-RunAtOutput-Plugin/SettingsForm.Designer.cs @@ -0,0 +1,211 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +namespace RunAtOutput { + partial class SettingsForm { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.textBox_commandline = new System.Windows.Forms.TextBox(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOk = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.textBox_arguments = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.listView1 = new System.Windows.Forms.ListView(); + this.columnHeader1 = new System.Windows.Forms.ColumnHeader(); + this.columnHeader2 = new System.Windows.Forms.ColumnHeader(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.textBox_name = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // textBox_commandline + // + this.textBox_commandline.Location = new System.Drawing.Point(229, 245); + this.textBox_commandline.Name = "textBox_commandline"; + this.textBox_commandline.Size = new System.Drawing.Size(184, 20); + this.textBox_commandline.TabIndex = 2; + // + // buttonCancel + // + this.buttonCancel.Location = new System.Drawing.Point(339, 302); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 7; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.ButtonCancelClick); + // + // buttonOk + // + this.buttonOk.Location = new System.Drawing.Point(258, 302); + this.buttonOk.Name = "buttonOk"; + this.buttonOk.Size = new System.Drawing.Size(75, 23); + this.buttonOk.TabIndex = 6; + this.buttonOk.Text = "OK"; + this.buttonOk.UseVisualStyleBackColor = true; + this.buttonOk.Click += new System.EventHandler(this.ButtonOkClick); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(153, 248); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(56, 17); + this.label1.TabIndex = 3; + this.label1.Text = "Command"; + // + // textBox_arguments + // + this.textBox_arguments.Location = new System.Drawing.Point(229, 271); + this.textBox_arguments.Name = "textBox_arguments"; + this.textBox_arguments.Size = new System.Drawing.Size(184, 20); + this.textBox_arguments.TabIndex = 3; + // + // label2 + // + this.label2.Location = new System.Drawing.Point(153, 274); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(70, 17); + this.label2.TabIndex = 5; + this.label2.Text = "Arguments"; + // + // listView1 + // + this.listView1.CheckBoxes = true; + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2}); + this.listView1.FullRowSelect = true; + this.listView1.Location = new System.Drawing.Point(13, 13); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(400, 183); + this.listView1.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.ListView1ItemChecked); + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1ItemSelectionChanged); + // + // columnHeader1 + // + this.columnHeader1.Text = "Active"; + // + // columnHeader2 + // + this.columnHeader2.Text = "Name"; + this.columnHeader2.Width = 311; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(13, 202); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 4; + this.button1.Text = "Add"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.ButtonAddClick); + // + // button2 + // + this.button2.Location = new System.Drawing.Point(12, 231); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 5; + this.button2.Text = "Delete"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.ButtonDeleteClick); + // + // label3 + // + this.label3.Location = new System.Drawing.Point(154, 222); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(56, 17); + this.label3.TabIndex = 10; + this.label3.Text = "Name"; + // + // textBox_name + // + this.textBox_name.Location = new System.Drawing.Point(230, 219); + this.textBox_name.Name = "textBox_name"; + this.textBox_name.Size = new System.Drawing.Size(184, 20); + this.textBox_name.TabIndex = 1; + // + // SettingsForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(426, 336); + this.Controls.Add(this.label3); + this.Controls.Add(this.textBox_name); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.listView1); + this.Controls.Add(this.label2); + this.Controls.Add(this.textBox_arguments); + this.Controls.Add(this.label1); + this.Controls.Add(this.buttonOk); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.textBox_commandline); + this.Name = "SettingsForm"; + this.Text = "Command Editor"; + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.TextBox textBox_name; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.TextBox textBox_arguments; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox_commandline; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button buttonOk; + private System.Windows.Forms.Button buttonCancel; + } +} diff --git a/Greenshot-RunAtOutput-Plugin/SettingsForm.cs b/Greenshot-RunAtOutput-Plugin/SettingsForm.cs new file mode 100644 index 000000000..258f66fa7 --- /dev/null +++ b/Greenshot-RunAtOutput-Plugin/SettingsForm.cs @@ -0,0 +1,98 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Windows.Forms; + +namespace RunAtOutput { + /// + /// Description of SettingsForm. + /// + public partial class SettingsForm : Form { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(SettingsForm)); + private Configuration config; + + public SettingsForm(Configuration config) { + this.config = config; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + UpdateView(); + } + + void ButtonOkClick(object sender, EventArgs e) { + DialogResult = DialogResult.OK; + } + + void ButtonCancelClick(object sender, EventArgs e) { + DialogResult = DialogResult.Cancel; + } + + void ShowSelectedItem() { + foreach ( ListViewItem item in listView1.SelectedItems ) { + Commando commando = item.Tag as Commando; + textBox_arguments.Text = commando.Arguments; + textBox_commandline.Text = commando.Commandline; + textBox_name.Text = commando.Name; + } + } + + void ButtonAddClick(object sender, EventArgs e) { + Commando commando = new Commando(); + commando.Arguments = textBox_arguments.Text; + commando.Commandline = textBox_commandline.Text; + commando.Name = textBox_name.Text; + config.Commands.Add(commando); + UpdateView(); + } + + void ButtonDeleteClick(object sender, EventArgs e) { + foreach ( ListViewItem item in listView1.SelectedItems ) { + Commando commando = item.Tag as Commando; + config.Commands.Remove(commando); + } + UpdateView(); + } + + void UpdateView() { + listView1.Items.Clear(); + foreach(Commando commando in config.Commands) { + ListViewItem item = new ListViewItem(""); + item.SubItems.Add(commando.Name); + item.Checked = commando.Active; + item.Tag = commando; + listView1.Items.Add(item); + } + } + + + void ListView1ItemSelectionChanged(object sender, EventArgs e) { + ShowSelectedItem(); + } + + void ListView1ItemChecked(object sender, ItemCheckedEventArgs e) { + Commando commando = e.Item.Tag as Commando; + LOG.Debug("ItemChecked " + commando.Name + " to " + e.Item.Checked); + commando.Active = e.Item.Checked; + } + } +} diff --git a/Greenshot-RunAtOutput-Plugin/runatoutput.properties b/Greenshot-RunAtOutput-Plugin/runatoutput.properties new file mode 100644 index 000000000..826cb81e5 --- /dev/null +++ b/Greenshot-RunAtOutput-Plugin/runatoutput.properties @@ -0,0 +1,4 @@ +active=OptiPNG,Paint.NET +command.Paint.NET=C:\Programme\Paint.NET\PaintDotNet.exe {0} +pattern.OptiPNG=*.png +command.OptiPNG=D:\05018085\downloads\optipng-0.6.4-exe\optipng.exe {0} diff --git a/Greenshot-TitleFix-Plugin/FixTitle.cs b/Greenshot-TitleFix-Plugin/FixTitle.cs new file mode 100644 index 000000000..4a88196df --- /dev/null +++ b/Greenshot-TitleFix-Plugin/FixTitle.cs @@ -0,0 +1,127 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +using Greenshot.Plugin; +using GreenshotPlugin.Core; + +namespace FixTitle { + /// + /// An example Plugin so developers can see how they can develop their own plugin + /// + public class FixTitle : IGreenshotPlugin { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FixTitle)); + private const string CONFIG_FILE_NAME = "titlefix.properties"; + private const string ACTIVE_PROPERTY = "active"; + private const string REGEXP_PROPERTY = ".regexp"; + private const string REPLACE_PROPERTY = ".replace"; + + private IGreenshotPluginHost host; + private ICaptureHost captureHost = null; + private PluginAttribute myAttributes; + private Properties config = null; + + public FixTitle() { + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// Use the IGreenshotPluginHost interface to register events + /// Use the ICaptureHost interface to register in the MainContextMenu + /// My own attributes + public virtual void Initialize(IGreenshotPluginHost pluginHost, ICaptureHost captureHost, PluginAttribute myAttributes) { + LOG.Debug("Initialize called of " + myAttributes.Name); + + this.host = (IGreenshotPluginHost)pluginHost; + this.captureHost = captureHost; + this.myAttributes = myAttributes; + + LoadConfig(); + + if (config != null) { + this.host.OnCaptureTaken += new OnCaptureTakenHandler(CaptureTaken); + } else { + LOG.Warn("Not registering FixTitle plugin due to missing configuration"); + } + + } + + public virtual void Shutdown() { + LOG.Debug("Shutdown of " + myAttributes.Name); + this.host.OnCaptureTaken -= new OnCaptureTakenHandler(CaptureTaken); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public virtual void Configure() { + LOG.Debug("Configure called"); + } + + /// + /// Implementation of the OnCaptureTaken event + /// + private void CaptureTaken(object sender, CaptureTakenEventArgs eventArgs) { + string title = eventArgs.Capture.CaptureDetails.Title; + LOG.Debug("Title before: " + title); + if (title != null && title.Length > 0) { + title = title.Trim(); + foreach(string titleIdentifier in config.GetPropertyAsArray(ACTIVE_PROPERTY)) { + string regexpString = config.GetProperty(titleIdentifier + REGEXP_PROPERTY); + string replaceString = config.GetProperty(titleIdentifier + REPLACE_PROPERTY); + if (regexpString != null && regexpString.Length > 0) { + Regex regex = new Regex(regexpString); + title = regex.Replace(title, replaceString); + } + } + } + LOG.Debug("Title after: " + title); + eventArgs.Capture.CaptureDetails.Title = title; + } + + private void LoadConfig() { + string configfilename = Path.Combine(host.ConfigurationPath, CONFIG_FILE_NAME); + if (File.Exists(configfilename)) { + config = Properties.read(configfilename); + } else { + config = new Properties(); + } + // Check if we have a configuration + if (!config.ContainsKey(ACTIVE_PROPERTY)) { + // Create default with FireFox + config.AddProperty("Firefox"+REGEXP_PROPERTY, " - Mozilla Firefox.*"); + config.AddProperty("Firefox"+REPLACE_PROPERTY, ""); + // and IE + config.AddProperty("IE"+REGEXP_PROPERTY, " - Microsoft Internet Explorer.*"); + config.AddProperty("IE"+REPLACE_PROPERTY, ""); + // Activate both + config.AddProperty(ACTIVE_PROPERTY, "IE,Firefox"); + config.write(configfilename); + } + } + } +} \ No newline at end of file diff --git a/Greenshot-TitleFix-Plugin/Greenshot-TitleFix-Plugin.csproj b/Greenshot-TitleFix-Plugin/Greenshot-TitleFix-Plugin.csproj new file mode 100644 index 000000000..938eac514 --- /dev/null +++ b/Greenshot-TitleFix-Plugin/Greenshot-TitleFix-Plugin.csproj @@ -0,0 +1,66 @@ + + + {0A07500E-7404-48D7-8789-7EB2A23E0DD5} + Debug + x86 + Library + Greenshot_TitleFix_Plugin + Greenshot-TitleFix-Plugin + v2.0 + Properties + C:\Dokumente und Einstellungen\05018085\Anwendungsdaten\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis + False + False + 4 + false + OnBuildSuccess + + + x86 + False + Auto + 4194304 + 4096 + + + bin\Debug\ + true + Full + False + True + DEBUG;TRACE + + + bin\Release\ + False + None + True + False + TRACE + + + + + ..\Greenshot\Lib\log4net.dll + + + + + + + + + + + mkdir "$(SolutionDir)bin\$(Configuration)\Plugins\$(ProjectName)" +copy "$(ProjectDir)bin\$(Configuration)\$(TargetFileName)" "$(SolutionDir)bin\$(Configuration)\Plugins\$(ProjectName)\*.gsp" + + "$(SolutionDir)\tools\TortoiseSVN\SubWCRev.exe" "$(SolutionDir)\" "$(ProjectDir)\Properties\AssemblyInfo.cs.template" "$(ProjectDir)\Properties\AssemblyInfo.cs" + + + + {5B924697-4DCD-4F98-85F1-105CB84B7341} + GreenshotPlugin + + + \ No newline at end of file diff --git a/Greenshot-TitleFix-Plugin/Properties/AssemblyInfo.cs.template b/Greenshot-TitleFix-Plugin/Properties/AssemblyInfo.cs.template new file mode 100644 index 000000000..ea4281eef --- /dev/null +++ b/Greenshot-TitleFix-Plugin/Properties/AssemblyInfo.cs.template @@ -0,0 +1,54 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +#region Using directives + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Plugin; + +#endregion + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Greenshot-TitleFix-Plugin")] +[assembly: AssemblyDescription("A plugin to fix captured Window Titles")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Greenshot-TitleFix-Plugin")] +[assembly: AssemblyCopyright("Copyright 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +// The PluginAttribute describes the "entryType" and if the plugin is configurable +[assembly: PluginAttribute("FixTitle.FixTitle", false)] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all the values or you can use the default the Revision and +// Build Numbers by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.$WCREV$")] diff --git a/Greenshot/AssemblyInfo.cs b/Greenshot/AssemblyInfo.cs new file mode 100644 index 000000000..3aac15d4b --- /dev/null +++ b/Greenshot/AssemblyInfo.cs @@ -0,0 +1,51 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("Greenshot")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Greenshot")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly: AssemblyVersion("0.8.0.0")] diff --git a/Greenshot/AssemblyInfo.cs.template b/Greenshot/AssemblyInfo.cs.template new file mode 100644 index 000000000..206669e41 --- /dev/null +++ b/Greenshot/AssemblyInfo.cs.template @@ -0,0 +1,51 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("Greenshot")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Greenshot")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly: AssemblyVersion("0.8.0.$WCREV$")] diff --git a/Greenshot/Configuration/AppConfig.cs b/Greenshot/Configuration/AppConfig.cs new file mode 100644 index 000000000..f89338a03 --- /dev/null +++ b/Greenshot/Configuration/AppConfig.cs @@ -0,0 +1,320 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Threading; +using System.Windows.Forms; + +using Greenshot.Drawing; +using Greenshot.Drawing.Fields; +using GreenshotPlugin.Core; + +namespace Greenshot.Configuration { + public enum ScreenshotDestinations {Editor=1, FileDefault=2, FileWithDialog=4, Clipboard=8, Printer=16, EMail=32} + + /// + /// AppConfig is used for loading and saving the configuration. All public fields + /// in this class are serialized with the BinaryFormatter and then saved to the + /// config file. After loading the values from file, SetDefaults iterates over + /// all public fields an sets fields set to null to the default value. + /// + [Serializable] + public class AppConfig { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(AppConfig)); + + //private static string loc = Assembly.GetExecutingAssembly().Location; + //private static string oldFilename = Path.Combine(loc.Substring(0,loc.LastIndexOf(@"\")),"config.dat"); + private const string CONFIG_FILE_NAME = "config.dat"; + private static string configfilepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),@"Greenshot\"); + private static AppConfig instance = null; + + public Dictionary LastUsedFieldValues = new Dictionary(); + + // the configuration part - all public vars are stored in the config file + // don't use "null" and "0" as default value! + + #region general application config + public bool? General_RegisterHotkeys = true; + public bool? General_IsFirstLaunch = true; + #endregion + + #region capture config + public bool? Capture_Mousepointer = true; + public bool? Capture_Windows_Interactive = false; + public int Capture_Wait_Time = 100; + public bool? Capture_Complete_Window = false; + public bool? Capture_Window_Content = false; + #endregion + + #region user interface config + public string Ui_Language = ""; + public bool? Ui_Effects_Flashlight = false; + public bool? Ui_Effects_CameraSound = true; + #endregion + + #region output config + public ScreenshotDestinations Output_Destinations = ScreenshotDestinations.Editor; + + + public string Output_File_Path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + public string Output_File_FilenamePattern = "%title%_%YYYY%-%MM%-%DD%_%hh%-%mm%-%ss%"; + public string Output_File_Format = ImageFormat.Png.ToString(); + public bool? Output_File_CopyPathToClipboard = false; + public int Output_File_JpegQuality = 80; + public bool? Output_File_PromptJpegQuality = false; + public int Output_File_IncrementingNumber = 1; + + public string Output_FileAs_Fullpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"dummy.png"); + + public bool? Output_Print_PromptOptions = true; + public bool? Output_Print_AllowRotate = true; + public bool? Output_Print_AllowEnlarge = true; + public bool? Output_Print_AllowShrink = true; + public bool? Output_Print_Center = true; + public bool? Output_Print_Timestamp = true; + #endregion + + #region editor config + public Size Editor_WindowSize = new Size(540, 380); + public Point Editor_WindowLocation = new Point(100, 100); + public String Editor_WindowState = "Normal"; + public Rectangle Editor_Previous_Screenbounds = Rectangle.Empty; + public Color[] Editor_RecentColors = new Color[12]; + public Font Editor_Font = null; + + #endregion + + /// + /// a private constructor because this is a singleton + /// + private AppConfig() { + } + + /// + /// get an instance of AppConfig + /// + /// + public static AppConfig GetInstance() { + if (instance == null) { + instance = Load(); + } + return instance; + } + + public static void Reload() { + AppConfig newInstance = Load(); + instance.Copy(newInstance); + } + + /// + /// loads the configuration from the config file + /// + /// an instance of AppConfig with all values set from the config file + private static AppConfig Load() { + AppConfig conf; + CheckConfigFile(); + string configfilename = Path.Combine(configfilepath, CONFIG_FILE_NAME); + try { + LOG.Debug("Loading configuration from: " + configfilename); + using (FileStream fileStream = File.Open(configfilename, FileMode.Open, FileAccess.Read)) { + BinaryFormatter binaryFormatter = new BinaryFormatter(); + conf = (AppConfig) binaryFormatter.Deserialize(fileStream); + } + conf.SetDefaults(); + return conf; + } catch (SerializationException e) { + LOG.Error("Problem loading configuration from: " + configfilename, e); + AppConfig config = new AppConfig(); + config.Store(); + return config; + } catch (Exception e) { + LOG.Error("Problem loading configuration from: " + configfilename, e); + MessageBox.Show(String.Format("Could not load Greenshot's configuration file. Please check access permissions for '{0}'.\n",configfilename),"Error"); + Process.GetCurrentProcess().Kill(); + } + return null; + } + + /// + /// Checks for the existence of a configuration file. + /// First in greenshot's Applicationdata folder (where it is stored since 0.6), + /// then (if it cannot be found there) in greenshot's program directory (where older + /// versions might have stored it). + /// If the latter is the case, the file is moved to the new location, so that a user does not lose + /// their configuration after upgrading. + /// If there is no file in both locations, a virgin config file is created. + /// + private static void CheckConfigFile() { + // check if file is in the same location as started from, if this is the case + // we will use this file instead of the Applicationdate folder + // Done for Feature Request #2741508 + if (File.Exists(Path.Combine(Application.StartupPath, CONFIG_FILE_NAME))) { + configfilepath = Application.StartupPath; + } else if (!File.Exists(Path.Combine(configfilepath, CONFIG_FILE_NAME))) { + Directory.CreateDirectory(configfilepath); + new AppConfig().Store(); + } + } + + /// + /// saves the configuration values to the supplied config file + /// + public void Store() { + Store(configfilepath); + } + + /// + /// saves the configuration values to the config path + /// + public void Store(string configpath) { + string configfilename = Path.Combine(configpath, CONFIG_FILE_NAME); + try { + LOG.Debug("Saving configuration to: " + configfilename); + using (FileStream fileStream = File.Open(configfilename, FileMode.Create)) { + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(fileStream, this); + } + } catch (UnauthorizedAccessException e) { + LOG.Error("Problem saving configuration to: " + configfilename, e); + MessageBox.Show(Language.GetInstance().GetFormattedString(LangKey.config_unauthorizedaccess_write,configfilename),Language.GetInstance().GetString(LangKey.error)); + } + } + + /// + /// when new fields are added to this class, they are instanced + /// with null by default. this method iterates over all public + /// fields and uses reflection to set them to the proper default value. + /// + public void SetDefaults() { + Type type = this.GetType(); + FieldInfo[] fieldInfos = type.GetFields(); + foreach (FieldInfo fi in fieldInfos) { + object o = fi.GetValue(this); + int i; + if (o == null || (int.TryParse(o.ToString(), out i) && i == 0)) { + // found field with value null. setting to default. + AppConfig tmpConf = new AppConfig(); + Type tmpType = tmpConf.GetType(); + FieldInfo defaultField = tmpType.GetField(fi.Name); + fi.SetValue(this, defaultField.GetValue(tmpConf)); + } + } + } + + private void Copy(AppConfig newConfig) { + Type type = this.GetType(); + + // Copy fields + FieldInfo[] fieldInfos = type.GetFields(); + foreach (FieldInfo fi in fieldInfos) { + object newValue = fi.GetValue(newConfig); + fi.SetValue(this, newValue); + } + // Update language + if (newConfig.Ui_Language != null && !newConfig.Ui_Language.Equals(Language.GetInstance().CurrentLanguage)) { + string newLang = Language.GetInstance().SetLanguage(newConfig.Ui_Language); + // check if the language was not wat was supplied (near match) + if (newConfig.Ui_Language.Equals(newLang)) { + // Store change + this.Store(); + } + } + } + + public static Properties GetAvailableProperties() { + Properties properties = new Properties(); + Type type = typeof(AppConfig); + FieldInfo[] fieldInfos = type.GetFields(); + foreach (FieldInfo fi in fieldInfos) { + Type fieldType = fi.FieldType; + if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { + // We are dealing with a generic type that is nullable + fieldType = Nullable.GetUnderlyingType(fieldType); + } + if (fieldType == typeof(string) || fieldType == typeof(bool) || fieldType == typeof(int)) { + properties.AddProperty(fi.Name, fieldType.Name); + } + } + return properties; + } + + public void SetProperties(Properties properties) { + Type type = this.GetType(); + FieldInfo[] fieldInfos = type.GetFields(); + foreach(string key in properties.Keys) { + FieldInfo currentField = type.GetField(key); + if (currentField != null) { + object currentValue = currentField.GetValue(this); + LOG.Debug("Before: " + currentField.Name + "=" + currentValue); + if (currentField.FieldType == typeof(string)) { + currentField.SetValue(this, properties.GetProperty(key)); + } else if (currentField.FieldType == typeof(bool) ||currentField.FieldType == typeof(bool?)) { + currentField.SetValue(this, properties.GetBoolProperty(key)); + } else if (currentField.FieldType == typeof(int) || currentField.FieldType == typeof(int?)) { + currentField.SetValue(this, properties.GetIntProperty(key)); + } + LOG.Debug("After: " + currentField.Name + "=" + currentField.GetValue(this)); + } else { + LOG.Warn("Configuration for " + key + " not found! (Incorrect key?)"); + } + } + } + + public void UpdateLastUsedFieldValue(Field f) { + if(f.Value != null) { + string key = GetKeyForField(f); + LastUsedFieldValues[key] = f.Value; + } + } + + public Field GetLastUsedValueForField(Field f, object preferredDefaultValue) { + string key = GetKeyForField(f); + if(LastUsedFieldValues.ContainsKey(key)) { + f.Value = LastUsedFieldValues[key]; + } else if(preferredDefaultValue != null) { + f.Value = preferredDefaultValue; + }else { + f.Value = f.FieldType.DefaultValue; + } + return f; + } + + /// + /// + /// + /// the key under which last used value for the Field can be stored/retrieved + private string GetKeyForField(Field f) { + if(f.Scope == null) { + return f.FieldType.Name; + } else { + return f.FieldType.Name + "-" + f.Scope; + } + } + } +} diff --git a/Greenshot/Configuration/Language.cs b/Greenshot/Configuration/Language.cs new file mode 100644 index 000000000..cbf3d8d40 --- /dev/null +++ b/Greenshot/Configuration/Language.cs @@ -0,0 +1,51 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using System.Xml; + +using GreenshotPlugin.Core; + +namespace Greenshot.Configuration { + /// + /// Wrapper for the language container for the Greenshot base. + /// + public class Language : LanguageContainer, ILanguage { + private static ILanguage uniqueInstance; + private const string LANGUAGE_FILENAME_PATTERN = @"language-*.xml"; + + public static ILanguage GetInstance() { + if(uniqueInstance == null) { + uniqueInstance = new LanguageContainer(); + uniqueInstance.LanguageFilePattern = LANGUAGE_FILENAME_PATTERN; + uniqueInstance.Load(); + uniqueInstance.SetLanguage(AppConfig.GetInstance().Ui_Language); + Thread.CurrentThread.CurrentUICulture = new CultureInfo(uniqueInstance.CurrentLanguage); + } + return uniqueInstance; + } + } +} diff --git a/Greenshot/Configuration/LanguageKeys.cs b/Greenshot/Configuration/LanguageKeys.cs new file mode 100644 index 000000000..f7d04132e --- /dev/null +++ b/Greenshot/Configuration/LanguageKeys.cs @@ -0,0 +1,191 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +namespace Greenshot.Configuration { + public enum LangKey { + about_bugs, + about_donations, + about_host, + about_icons, + about_license, + about_title, + about_translation, + application_title, + bugreport_cancel, + bugreport_info, + bugreport_title, + clipboard_error, + clipboard_inuse, + colorpicker_alpha, + colorpicker_apply, + colorpicker_blue, + colorpicker_green, + colorpicker_htmlcolor, + colorpicker_recentcolors, + colorpicker_red, + colorpicker_title, + colorpicker_transparent, + config_unauthorizedaccess_write, + contextmenu_about, + contextmenu_capturearea, + contextmenu_captureclipboard, + contextmenu_capturefullscreen, + contextmenu_capturelastregion, + contextmenu_capturewindow, + contextmenu_donate, + contextmenu_exit, + contextmenu_help, + contextmenu_openfile, + contextmenu_quicksettings, + contextmenu_settings, + editor_arrange, + editor_arrowheads, + editor_arrowheads_both, + editor_arrowheads_end, + editor_arrowheads_none, + editor_arrowheads_start, + editor_backcolor, + editor_blur_radius, + editor_bold, + editor_brightness, + editor_cancel, + editor_clipboardfailed, + editor_close, + editor_close_on_save, + editor_close_on_save_title, + editor_confirm, + editor_copyimagetoclipboard, + editor_copypathtoclipboard, + editor_copytoclipboard, + editor_crop, + editor_cursortool, + editor_cuttoclipboard, + editor_deleteelement, + editor_downonelevel, + editor_downtobottom, + editor_drawarrow, + editor_drawellipse, + editor_drawhighlighter, + editor_drawline, + editor_drawrectangle, + editor_drawtextbox, + editor_duplicate, + editor_edit, + editor_email, + editor_file, + editor_fontsize, + editor_forecolor, + editor_highlight_area, + editor_highlight_grayscale, + editor_highlight_mode, + editor_highlight_text, + editor_highlight_magnify, + editor_pixel_size, + editor_imagesaved, + editor_italic, + editor_load_objects, + editor_magnification_factor, + editor_obfuscate, + editor_obfuscate_blur, + editor_obfuscate_mode, + editor_obfuscate_pixelize, + editor_object, + editor_opendirinexplorer, + editor_pastefromclipboard, + editor_preview_quality, + editor_print, + editor_save, + editor_save_objects, + editor_saveas, + editor_selectall, + editor_senttoprinter, + editor_shadow, + editor_storedtoclipboard, + editor_thickness, + editor_title, + editor_uponelevel, + editor_uptotop, + error, + error_multipleinstances, + error_nowriteaccess, + error_openfile, + error_openlink, + error_save, + help_title, + jpegqualitydialog_choosejpegquality, + jpegqualitydialog_dontaskagain, + jpegqualitydialog_title, + print_error, + printoptions_allowcenter, + printoptions_allowenlarge, + printoptions_allowrotate, + printoptions_allowshrink, + printoptions_dontaskagain, + printoptions_timestamp, + printoptions_title, + quicksettings_destination_file, + settings_alwaysshowjpegqualitydialog, + settings_alwaysshowprintoptionsdialog, + settings_applicationsettings, + settings_autostartshortcut, + settings_capture, + settings_capture_mousepointer, + settings_capture_windows_interactive, + settings_capture_window_full, + settings_capture_window_content, + settings_copypathtoclipboard, + settings_destination, + settings_destination_clipboard, + settings_destination_editor, + settings_destination_email, + settings_destination_file, + settings_destination_fileas, + settings_destination_printer, + settings_filenamepattern, + settings_general, + settings_jpegquality, + settings_jpegsettings, + settings_language, + settings_message_filenamepattern, + settings_output, + settings_playsound, + settings_preferredfilesettings, + settings_primaryimageformat, + settings_printer, + settings_printoptions, + settings_registerhotkeys, + settings_showflashlight, + settings_skipimageeditor, + settings_storagelocation, + settings_title, + settings_tooltip_filenamepattern, + settings_tooltip_language, + settings_tooltip_primaryimageformat, + settings_tooltip_registerhotkeys, + settings_tooltip_storagelocation, + settings_visualization, + settings_waittime, + tooltip_firststart, + warning, + warning_hotkeys + } +} diff --git a/Greenshot/Configuration/RuntimeConfig.cs b/Greenshot/Configuration/RuntimeConfig.cs new file mode 100644 index 000000000..3f9edf51c --- /dev/null +++ b/Greenshot/Configuration/RuntimeConfig.cs @@ -0,0 +1,37 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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.Imaging; +using System.Drawing; +using System.Windows.Forms; +using System; + +namespace Greenshot.Configuration { + /// + /// Greenshot's runtime configuration + /// abstract, all properties are public and static + /// + public abstract class RuntimeConfig { + public static string[] SupportedLanguages = {"en-US","de-DE"}; + public static string[] SupportedImageFormats = {ImageFormat.Jpeg.ToString(),ImageFormat.Gif.ToString(),ImageFormat.Png.ToString(),ImageFormat.Bmp.ToString()}; + public static string BugTrackerUrl = "https://sourceforge.net/tracker/?func=postadd&group_id=191585&atid=937972&summary=%SUMMARY%&details=%DETAILS%"; + public static Rectangle LastCapturedRegion = Rectangle.Empty; + } +} diff --git a/Greenshot/Controls/BindableToolStripButton.cs b/Greenshot/Controls/BindableToolStripButton.cs new file mode 100644 index 000000000..ce7a509de --- /dev/null +++ b/Greenshot/Controls/BindableToolStripButton.cs @@ -0,0 +1,41 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.ComponentModel; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace Greenshot.Controls { + /// + /// Description of BindableToolStripButton. + /// + public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged { + public event PropertyChangedEventHandler PropertyChanged; + + public BindableToolStripButton() :base() { + this.CheckedChanged += new EventHandler(BindableToolStripButton_CheckedChanged); + } + + void BindableToolStripButton_CheckedChanged(object sender, EventArgs e) { + if(PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Checked")); + } + } +} diff --git a/Greenshot/Controls/BindableToolStripComboBox.cs b/Greenshot/Controls/BindableToolStripComboBox.cs new file mode 100644 index 000000000..1dfcbf945 --- /dev/null +++ b/Greenshot/Controls/BindableToolStripComboBox.cs @@ -0,0 +1,44 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.ComponentModel; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace Greenshot.Controls { + /// + /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding + /// + public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged { + public event PropertyChangedEventHandler PropertyChanged; + + public BindableToolStripComboBox() :base() { + this.SelectedIndexChanged += new EventHandler(BindableToolStripComboBox_SelectedIndexChanged); + } + + void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) { + if(PropertyChanged != null) { + PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem")); + + } + } + } +} diff --git a/Greenshot/Controls/BindableToolStripDropDownButton.cs b/Greenshot/Controls/BindableToolStripDropDownButton.cs new file mode 100644 index 000000000..87078a30d --- /dev/null +++ b/Greenshot/Controls/BindableToolStripDropDownButton.cs @@ -0,0 +1,68 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.ComponentModel; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace Greenshot.Controls { + /// + /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding. + /// Also, when a DropDownItem is selected, the DropDownButton adops its Tag and Image. + /// The selected tag can be accessed via SelectedTag property. + /// + public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged { + + public event PropertyChangedEventHandler PropertyChanged; + + public BindableToolStripDropDownButton() { + } + + 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; + if(PropertyChanged != null) PropertyChanged(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; + if(PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("SelectedTag")); + } + } + } +} diff --git a/Greenshot/Controls/ColorButton.cs b/Greenshot/Controls/ColorButton.cs new file mode 100644 index 000000000..80a9ac8d8 --- /dev/null +++ b/Greenshot/Controls/ColorButton.cs @@ -0,0 +1,82 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; +using System.Windows.Forms; +using Greenshot.Configuration; + +namespace Greenshot.Controls { + public class ColorButton : ToolStripButton, INotifyPropertyChanged { + public event PropertyChangedEventHandler PropertyChanged; + + private Color selectedColor = Color.Transparent; + + public ColorButton() { + Bitmap bmp = new Bitmap(1,1); + bmp.SetPixel(0,0, selectedColor); + this.Image = bmp; + this.BackgroundImageLayout = ImageLayout.Tile; + Click+= new EventHandler(ColorButtonClick); + } + + public Color SelectedColor { + get {return selectedColor;} + set { + //(Image as Bitmap).SetPixel(0,0, value); + selectedColor = value; + + Brush brush; + if(value != Color.Transparent) { + brush = new SolidBrush(value); + } else { + brush = new HatchBrush(HatchStyle.Percent50,Color.White, Color.Gray); + } + + using (Graphics graphics = Graphics.FromImage(Image)) { + graphics.FillRectangle(brush, new Rectangle(0,13,16,3)); + } + // cleanup GDI Object + brush.Dispose(); + Invalidate(); + } + } + + void ColorButtonClick(object sender, EventArgs e) { + + ColorDialog colorDialog = ColorDialog.GetInstance(); + colorDialog.Color = SelectedColor; + colorDialog.ShowDialog(); + if (colorDialog.DialogResult != DialogResult.Cancel) { + if(!colorDialog.Color.Equals(SelectedColor)) { + AppConfig conf = AppConfig.GetInstance(); + conf.Editor_RecentColors = colorDialog.RecentColors; + conf.Store(); + SelectedColor = colorDialog.Color; + if(PropertyChanged != null) { + PropertyChanged(this, new PropertyChangedEventArgs("SelectedColor")); + } + } + } + } + } +} diff --git a/Greenshot/Controls/FontFamilyComboBox.cs b/Greenshot/Controls/FontFamilyComboBox.cs new file mode 100644 index 000000000..a77154ccc --- /dev/null +++ b/Greenshot/Controls/FontFamilyComboBox.cs @@ -0,0 +1,62 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.ComponentModel; +using System.Windows.Forms; +using System.Windows.Forms.Design; +using System.Drawing; + +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() : base() + { + ComboBox.DataSource = FontFamily.Families; + ComboBox.DisplayMember = "Name"; + this.SelectedIndexChanged += new EventHandler(BindableToolStripComboBox_SelectedIndexChanged); + } + + void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + if(PropertyChanged != null) { + 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/ToolStripColorButton.cs b/Greenshot/Controls/ToolStripColorButton.cs new file mode 100644 index 000000000..8c26eef57 --- /dev/null +++ b/Greenshot/Controls/ToolStripColorButton.cs @@ -0,0 +1,64 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Windows.Forms; +using System.Windows.Forms.Design; +using System.Drawing; + +namespace Greenshot.Controls { + + /*[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] + public class ToolStripColorButton : ToolStripControlHost + { + public event EventHandler ValueChanged; + + public ToolStripColorButton() :base(new ColorButton()) + { + } + + public ColorButton ColorButton + { + get {return Control as ColorButton;} + } + + public Color SelectedColor + { + get { return ColorButton.SelectedColor; } + set { ColorButton.SelectedColor = value;} + } + + protected override void OnSubscribeControlEvents(Control control) + { + base.OnSubscribeControlEvents(control); + ColorButton.SelectedColorChanged += OnSelectedColorChanged; + } + protected override void OnUnsubscribeControlEvents(Control control) + { + base.OnUnsubscribeControlEvents(control); + ColorButton.SelectedColorChanged -= OnSelectedColorChanged; + } + + private void OnSelectedColorChanged(object sender, EventArgs e) + { + if(ValueChanged != null) ValueChanged(sender, e); + } + }*/ +} diff --git a/Greenshot/Controls/ToolStripNumericUpDown.cs b/Greenshot/Controls/ToolStripNumericUpDown.cs new file mode 100644 index 000000000..0797cfad2 --- /dev/null +++ b/Greenshot/Controls/ToolStripNumericUpDown.cs @@ -0,0 +1,81 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +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 + { + get {return 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) { + if(PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Value")); + } + } +} diff --git a/Greenshot/Drawing/ArrowContainer.cs b/Greenshot/Drawing/ArrowContainer.cs new file mode 100644 index 000000000..3235924e7 --- /dev/null +++ b/Greenshot/Drawing/ArrowContainer.cs @@ -0,0 +1,162 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.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) { + AddField(FieldFactory.CreateField(FieldType.ARROWHEADS)); + } + + public override void Draw(Graphics g, RenderMode rm) { + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS);; + + if ( shadow && lineThickness > 0 ) { + //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))) { + shadowCapPen.Width = lineThickness; + + if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) shadowCapPen.CustomStartCap = ARROW_CAP; + if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) shadowCapPen.CustomEndCap = ARROW_CAP; + + g.DrawLine(shadowCapPen, + this.Left + currentStep, + this.Top + currentStep, + this.Left + currentStep + this.Width, + this.Top + currentStep + this.Height); + + currentStep++; + alpha = alpha - (basealpha / steps); + } + } + } + + using (Pen pen = new Pen(lineColor)) { + pen.Width = lineThickness; + + if ( pen.Width > 0 ) { + if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) pen.CustomStartCap = ARROW_CAP; + if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) pen.CustomEndCap = ARROW_CAP; + + g.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); + } + + } + } + + public override bool ClickableAt(int x, int y) { + bool ret = false; + ret = base.ClickableAt(x, y); + if(!ret) { + // line has not been clicked, check arrow heads + ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); + if(!ArrowHeadCombination.NONE.Equals(heads)) { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + double arrowCapHalfWidth = ARROW_CAP.Width * lineThickness / 2; + double arrowCapHeight = ARROW_CAP.Height * lineThickness; + // we have to check only if arrow heads are wider than tolerated area of LineContainer + if(arrowCapHalfWidth > MAX_CLICK_DISTANCE_TOLERANCE) { + double mouseToLineDist = DrawingHelper.CalculateLinePointDistance(Left, Top, Left+Width, Top+Height, x, y); + if(mouseToLineDist > -1) { // point next to line at all? + if(heads.Equals(ArrowHeadCombination.END_POINT) || heads.Equals(ArrowHeadCombination.BOTH)) { + // calculate a perpendicular line at arrow tip to hittest arrow head easily + int p1x = Left + Width + Height; + int p1y = Top + Height - Width; + int p2x = Left + Width - Height; + int p2y = Top + Height + Width; + + double mouseToPerpDist = DrawingHelper.CalculateLinePointDistance(p1x,p1y,p2x,p2y, x, y); + if( + // point located within rectangular area of width/height of arrowhead? + mouseToLineDist <= arrowCapHalfWidth + && mouseToPerpDist <= arrowCapHeight + // point located within arrowhead? (nearer to line than to perp * w/h-factor) + && mouseToLineDist < mouseToPerpDist * arrowCapHalfWidth / arrowCapHeight) { + return true; + } + } + if(heads.Equals(ArrowHeadCombination.START_POINT) || heads.Equals(ArrowHeadCombination.BOTH)) { + // calculate a perpendicular line at arrow tip to hittest arrow head easily + int p1x = Left - Height; + int p1y = Top + Width; + int p2x = Left + Height; + int p2y = Top - Width; + + double mouseToPerpDist = DrawingHelper.CalculateLinePointDistance(p1x,p1y,p2x,p2y, x, y); + if( + // point located within rectangular area of width/height of arrowhead? + mouseToLineDist <= arrowCapHalfWidth + && mouseToPerpDist <= arrowCapHeight + // point located within arrowhead? (nearer to line than to perp * w/h-factor) + && mouseToLineDist < mouseToPerpDist * arrowCapHalfWidth / arrowCapHeight) { + return true; + } + + + } + } + + } + } + + } + + return ret; + + /*int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + double distance = DrawingHelper.CalculateLinePointDistance(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height, x, y); + if (distance < 0) { + return false; + } + return distance <= Math.Max(lineThickness / 2, 10);*/ + } + + } +} diff --git a/Greenshot/Drawing/BitmapBuffer.cs b/Greenshot/Drawing/BitmapBuffer.cs new file mode 100644 index 000000000..9eddc97c6 --- /dev/null +++ b/Greenshot/Drawing/BitmapBuffer.cs @@ -0,0 +1,322 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.Serialization; + +namespace Greenshot.Drawing { + /// + /// The BitmapBuffer is exactly what it says, it buffers a Bitmap. + /// And it is possible to Draw on the Bitmap with direct memory access for better performance + /// + [Serializable()] + public unsafe class BitmapBuffer : IDisposable { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BitmapBuffer)); + private Bitmap bitmap; + public Bitmap Bitmap { + get {return bitmap;} + } + [NonSerialized] + private BitmapData bmData; + [NonSerialized] + private Rectangle rect; + [NonSerialized] + private byte* pointer; + [NonSerialized] + private int stride; /* bytes per pixel row */ + [NonSerialized] + private int aIndex = -1; + [NonSerialized] + private int rIndex = -1; + [NonSerialized] + private int gIndex = -1; + [NonSerialized] + private int bIndex = -1; + [NonSerialized] + private int bytesPerPixel; + [NonSerialized] + private bool bitsLocked = false; + + public Size Size { + get {return rect.Size;} + } + public int Length { + get {return rect.Width*rect.Height;} + } + public int Width { + get {return rect.Width;} + } + public int Height { + get {return rect.Height;} + } + + /** + * Constructor with just a Bitmap, the Rectangle is the Bitmap itself + */ + public BitmapBuffer(Bitmap bmp) : this(bmp, Rectangle.Empty) { + } + + /** + * Create a BitmapBuffer from a Bitmap and a Rectangle specifying what part from the Bitmap to take + */ + public BitmapBuffer(Bitmap sourceBmp, Rectangle applyRect) { + Rectangle sourceRect = new Rectangle(applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height); + Rectangle bitmapRect = new Rectangle(0,0, sourceBmp.Width, sourceBmp.Height); + + if(sourceRect.Equals(Rectangle.Empty)) { + sourceRect = bitmapRect; + } else { + sourceRect.Intersect(bitmapRect); + } + // Does the rect have any pixels? + if (sourceRect.Height <= 0 || sourceRect.Width <= 0) { + return; + } + + if (SupportsPixelFormat(sourceBmp)) { + // Create copy with supported format + this.bitmap = sourceBmp.Clone(sourceRect, sourceBmp.PixelFormat); + } else { + // When sourceRect is the whole bitmap there is a GDI+ bug in Clone + // Clone will than return the same PixelFormat as the source + // a quick workaround is using new Bitmap which uses a default of Format32bppArgb + if (sourceRect.Equals(bitmapRect)) { + this.bitmap = new Bitmap(sourceBmp); + } else { + this.bitmap = sourceBmp.Clone(sourceRect, PixelFormat.Format24bppRgb); + } + } + // Set "this" rect to location 0,0 + // as the Cloned Bitmap is only the part we want to work with + this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + } + + /** + * Destructor + */ + ~BitmapBuffer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + // 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 virtual void Dispose(bool disposing) { + Unlock(); + if (disposing) { + if (bitmap != null) { + bitmap.Dispose(); + } + } + bitmap = null; + bmData = null; + pointer = null; + } + + /** + * This is called when deserializing the object + */ + public BitmapBuffer(SerializationInfo info, StreamingContext ctxt) { + this.bitmap = (Bitmap)info.GetValue("bitmap", typeof(Bitmap)); + this.rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + // The rest will be set when Lock is called + } + + /** + * This is called when serializing the object + */ + public void GetObjectData(SerializationInfo info, StreamingContext ctxt) { + Unlock(); + info.AddValue("bitmap", this.bitmap); + } + + /** + * Lock the bitmap so we have direct access to the memory + */ + public void Lock() { + if(rect.Width > 0 && rect.Height > 0) { + bmData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat); + bitsLocked = true; + + System.IntPtr Scan0 = bmData.Scan0; + pointer = (byte*)(void*)Scan0; + + PrepareForPixelFormat(); + stride = bmData.Stride; + } + } + + /** + * Unlock the System Memory + */ + private void Unlock() { + if(bitsLocked) { + bitmap.UnlockBits(bmData); + bitsLocked = false; + } + } + + /** + * Draw the stored bitmap to the destionation bitmap at the supplied point + */ + public void DrawTo(Graphics graphics, Point destination) { + DrawTo(graphics, null, destination); + } + + /** + * Draw the stored Bitmap on the Destination bitmap with the specified rectangle + * Be aware that the stored bitmap will be resized to the specified rectangle!! + */ + public void DrawTo(Graphics graphics, Rectangle destinationRect) { + DrawTo(graphics, destinationRect, null); + } + + /** + * private helper to draw the bitmap + */ + private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) { + if (destinationRect.HasValue) { + // Does the rect have any pixels? + if (destinationRect.Value.Height <= 0 || destinationRect.Value.Width <= 0) { + return; + } + } + // Make sure this.bitmap is unlocked + Unlock(); + + + if (destinationRect.HasValue) { + LOG.Debug(String.Format("Drawing at: {0},{1} {2},{3}", destinationRect.Value.X, destinationRect.Value.Y, destinationRect.Value.Width, destinationRect.Value.Height)); + graphics.DrawImage(this.bitmap, destinationRect.Value); + } else if (destination.HasValue) { + LOG.Debug(String.Format("Drawing at: {0},{1}", destination.Value.X, destination.Value.Y)); + graphics.DrawImage(this.bitmap, destination.Value); + } + } + + /** + * Retrieve the color at location x,y + * Before the first time this is called the Lock() should be called once! + */ + public Color GetColorAt(int x, int y) { + if(x>=0 && y>=0 && x=0 && y>=0 && x=0 && y>=0 && x=0 && y>=0 && x. + */ +using System; +using System.Drawing; +using System.IO; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of BitmapContainer. + /// + [Serializable()] + public class BitmapContainer : DrawableContainer, IBitmapContainer { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BitmapContainer)); + + protected Bitmap bitmap; + + public BitmapContainer(Surface parent, string filename) : this(parent) { + Load(filename); + } + + public BitmapContainer(Surface parent) : base(parent) { + } + + + public Bitmap Bitmap { + set { + if (bitmap != null) { + bitmap.Dispose(); + } + bitmap = (Bitmap)value.Clone(); + Width = value.Width; + Height = value.Height; + } + get { return bitmap; } + } + + /** + * Destructor + */ + ~BitmapContainer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public new void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + // 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 virtual void Dispose(bool disposing) { + if (disposing) { + if (bitmap != null) { + bitmap.Dispose(); + } + } + bitmap = null; + } + + public void Load(string filename) { + if (File.Exists(filename)) { + using (Bitmap fileBitmap = new Bitmap(filename)) { + Bitmap = fileBitmap; + LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); + } + } + } + + public override void Draw(Graphics g, RenderMode rm) { + if (bitmap != null) { + g.DrawImage(bitmap, Bounds); + } + } + } +} diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs new file mode 100644 index 000000000..84c61db56 --- /dev/null +++ b/Greenshot/Drawing/CropContainer.cs @@ -0,0 +1,57 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Helpers; +using Greenshot.Drawing.Fields; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of CropContainer. + /// + public class CropContainer : DrawableContainer { + public CropContainer(Surface parent) : base(parent) { + AddField(FieldFactory.CreateFieldWithValue(FieldType.FLAGS, FieldType.Flag.CONFIRMABLE)); + } + + public override void Draw(Graphics g, RenderMode rm) { + using (Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100))) { + Rectangle r = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); + Rectangle selectionRect = new Rectangle(r.Left - 1, r.Top - 1, r.Width + 1, r.Height + 1); + + DrawSelectionBorder(g, selectionRect); + + // top + g.FillRectangle(cropBrush, new Rectangle(0, 0, parent.Width, r.Top)); + // left + g.FillRectangle(cropBrush, new Rectangle(0, r.Top, r.Left, r.Height)); + // right + g.FillRectangle(cropBrush, new Rectangle(r.Left + r.Width, r.Top, parent.Width - (r.Left + r.Width), r.Height)); + // bottom + g.FillRectangle(cropBrush, new Rectangle(0, r.Top + r.Height, parent.Width, parent.Height - (r.Top + r.Height))); + } + } + } +} diff --git a/Greenshot/Drawing/CursorContainer.cs b/Greenshot/Drawing/CursorContainer.cs new file mode 100644 index 000000000..5c2d3f12f --- /dev/null +++ b/Greenshot/Drawing/CursorContainer.cs @@ -0,0 +1,110 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.IO; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of CursorContainer. + /// + [Serializable()] + public class CursorContainer : DrawableContainer, ICursorContainer { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(CursorContainer)); + + protected Cursor cursor; + + public CursorContainer(Surface parent) : base(parent) { + } + + public CursorContainer(Surface parent, string filename) : base(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; } + } + + /** + * Destructor + */ + ~CursorContainer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public new void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + // 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 virtual void Dispose(bool disposing) { + if (disposing) { + if (cursor != null) { + cursor.Dispose(); + } + } + cursor = null; + } + + public void Load(string filename) { + if (File.Exists(filename)) { + 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) { + cursor.DrawStretched(graphics, Bounds); + } + } + } +} diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs new file mode 100644 index 000000000..747ebe585 --- /dev/null +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -0,0 +1,403 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Controls; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; +using Greenshot.Helpers; +using Greenshot.Plugin; +using Greenshot.Plugin.Drawing; + +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, INotifyPropertyChanged, IDrawableContainer { + + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(DrawableContainer)); + + [NonSerialized] + private PropertyChangedEventHandler propertyChanged; + public event PropertyChangedEventHandler PropertyChanged { + add { propertyChanged += value; } + remove{ propertyChanged -= value; } + } + + + +// public List filters = new List(); + public List Filters { + get { + List ret = new List(); + foreach(IFieldHolder c in Children) { + if(c is IFilter) ret.Add(c as IFilter); + } + return ret; + } + } + + [NonSerialized] + protected Surface parent; + public ISurface Parent { + get { return parent; } + set { SwitchParent((Surface)value); } + } + [NonSerialized] + protected Label[] grippers; + private bool layoutSuspended = false; + [NonSerialized] + protected Label childLabel; + + [NonSerialized] + private bool selected = false; + public bool Selected { + get {return selected;} + set {selected = value; OnPropertyChanged("Selected"); } + } + + [NonSerialized] + public EditStatus Status = EditStatus.UNDRAWN; + + private int left = 0; + public int Left { + get { return left; } + set { left = value; DoLayout(); OnPropertyChanged("Left"); } + } + + private int top = 0; + public int Top { + get { return top; } + set { top = value; DoLayout(); OnPropertyChanged("Top"); } + } + + private int width = 0; + public int Width { + get { return width; } + set { width = value; DoLayout(); OnPropertyChanged("Width"); } + } + + private int height = 0; + public int Height { + get { return height; } + set { height = value; DoLayout(); OnPropertyChanged("Height"); } + } + + public Rectangle Bounds { + get { return GuiRectangle.GetGuiRectangle(left, top, width, height); } + } + + public DrawableContainer(Surface parent) { + this.parent = parent; + InitControls(); + } + + public void Add(IFilter filter) { + AddChild(filter); + } + + public void Remove(IFilter filter) { + RemoveChild(filter); + } + + public Label GetLabel() { + return childLabel; + } + + public void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) { + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + if (horizontalAlignment == HorizontalAlignment.Left) { + Left = lineThickness/2; + } + if (horizontalAlignment == HorizontalAlignment.Right) { + Left = parent.Width - this.Width - lineThickness/2; + } + if (horizontalAlignment == HorizontalAlignment.Center) { + Left = (parent.Width / 2) - (this.Width / 2) - lineThickness/2; + } + + if (verticalAlignment == VerticalAlignment.TOP) { + Top = lineThickness/2; + } + if (verticalAlignment == VerticalAlignment.BOTTOM) { + Top = parent.Height - this.Height - lineThickness/2; + } + if (verticalAlignment == VerticalAlignment.CENTER) { + Top = (parent.Height / 2) - (this.Height / 2) - lineThickness/2; + } + } + + public virtual bool InitContent() { return true; } + + public virtual void OnDoubleClick() {} + + private void InitControls() { + InitGrippers(); + childLabel = new Label(); + childLabel.BackColor = Color.Transparent; + childLabel.BorderStyle = BorderStyle.None; + childLabel.Cursor = Cursors.SizeAll; + childLabel.MouseDown += new MouseEventHandler(gripperMouseDown); + childLabel.MouseUp += new MouseEventHandler(gripperMouseUp); + childLabel.MouseMove += new MouseEventHandler(childLabelMouseMove); + + DoLayout(); + } + + void InitGrippers() { + grippers = new Label[8]; + for(int i=0; i grippers[4].Left && grippers[0].Top > grippers[4].Top) { + grippers[0].Cursor = Cursors.SizeNWSE; + grippers[2].Cursor = Cursors.SizeNESW; + grippers[4].Cursor = Cursors.SizeNWSE; + grippers[6].Cursor = Cursors.SizeNESW; + } else if((grippers[0].Left > grippers[4].Left && grippers[0].Top < grippers[4].Top) || + grippers[0].Left < grippers[4].Left && grippers[0].Top > grippers[4].Top) { + grippers[0].Cursor = Cursors.SizeNESW; + grippers[2].Cursor = Cursors.SizeNWSE; + grippers[4].Cursor = Cursors.SizeNESW; + grippers[6].Cursor = Cursors.SizeNWSE; + } else if (grippers[0].Left == grippers[4].Left) { + grippers[0].Cursor = Cursors.SizeNS; + grippers[4].Cursor = Cursors.SizeNS; + } else if (grippers[0].Top == grippers[4].Top) { + grippers[0].Cursor = Cursors.SizeWE; + grippers[4].Cursor = Cursors.SizeWE; + } + + childLabel.Left = this.Left; + childLabel.Top = this.Top; + childLabel.Width = this.Width; + childLabel.Height = this.Height; + } + } + + public virtual void Dispose() { + for(int i=0; i= 4 && gripperIndex <= 6) { // bottom row + this.Height += e.Y - my; + } + if(gripperIndex >=2 && gripperIndex <= 4) { // right row + this.Width += e.X - mx; + } else if(gripperIndex >=6 || gripperIndex == 0) { // left row + this.Left += e.X - mx; + this.Width -= e.X - mx; + } + ResumeLayout(); + parent.Invalidate(); + } + } + + private void childLabelMouseMove(object sender, MouseEventArgs e) { + if (Status.Equals(EditStatus.RESIZING)) { + SuspendLayout(); + this.Left += e.X - mx; + this.Top += e.Y - my; + ResumeLayout(); + parent.Invalidate(); + } + } + + public abstract void Draw(Graphics graphics, RenderMode renderMode); + + public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode) { + //if(LOG.IsDebugEnabled) LOG.Debug("Drawing container "+this+" with bounds "+Bounds+" and " + Children.Count + " children and status: "+Status); + if(Children.Count>0) { + if(!Status.Equals(EditStatus.IDLE)) { + DrawSelectionBorder(graphics, Bounds); + } else { + Rectangle effRect = Bounds; + + if(!effRect.IsEmpty) { + foreach(IFilter filter in Filters) { + //if(LOG.IsDebugEnabled) LOG.Debug("Applying filter "+filter+" with bounds "+effRect); + filter.Apply(graphics, bmp, effRect, renderMode); + } + } + + } + } + Draw(graphics, RenderMode.EDIT); + } + + 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)) { + pen.DashPattern = new float[]{1,2}; + pen.Width = 1; + g.DrawRectangle(pen, rect); + } + } + + public void ShowGrippers() { + for(int i=0; i. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +using Greenshot.Drawing.Fields; +using Greenshot.Plugin; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers. + /// + [Serializable()] + public class DrawableContainerList : List { + + public DrawableContainerList() { + } + + public EditStatus Status { + get { + return this[Count-1].Status; + } + set { + foreach(DrawableContainer dc in this) dc.Status = value; + } + } + + /// + /// 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(DrawableContainer dc in this) ret &= dc.Selected; + return ret; + } + set { + foreach(DrawableContainer 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 { + foreach(DrawableContainer dc in this) dc.Parent = value; + } + } + + /// + /// 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) { + foreach(DrawableContainer dc in this) { + dc.Left += dx; + dc.Top += dy; + } + } + + /// + /// Hides the grippers of all elements in the list. + /// + public void HideGrippers() { + foreach(DrawableContainer dc in this) { + dc.HideGrippers(); + } + } + + /// + /// Shows the grippers of all elements in the list. + /// + public void ShowGrippers() { + foreach(DrawableContainer dc in this) { + dc.ShowGrippers(); + } + } + + /// + /// 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(DrawableContainer 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 DrawableContainer 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(DrawableContainer dc in this) { + dc.OnDoubleClick(); + } + } + + /// + /// Triggers all elements in the list ot be redrawn. + /// + /// the related Graphics object + /// the rendermode in which the element is to be drawn + public void Draw(Graphics g, Bitmap bitmap, RenderMode rm) { + foreach(DrawableContainer dc in this) { + dc.DrawContent(g, bitmap, rm); + } + } + + /// + /// 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(DrawableContainerList elements) { + if(elements.Count == 0 || elements.Count == this.Count) return false; + foreach(DrawableContainer element in elements) { + if(this.IndexOf(element) < this.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(DrawableContainerList elements) { + for(int i=this.Count-1; i>=0; i--) { + DrawableContainer dc = this[i]; + if(elements.Contains(dc)) { + 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(DrawableContainerList elements) { + DrawableContainer[] dcs = this.ToArray(); + for(int i=0; i + /// 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(DrawableContainerList elements) { + if(elements.Count == 0 || elements.Count == this.Count) return false; + foreach(DrawableContainer element in elements) { + if(this.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(DrawableContainerList 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(DrawableContainerList elements) { + DrawableContainer[] dcs = this.ToArray(); + for(int i=dcs.Length-1; i>=0; i--) { + DrawableContainer dc = dcs[i]; + if(elements.Contains(dc)) { + this.Remove(dc); + this.Insert(0, dc); + } + } + } + + /// + /// 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) { + DrawableContainer dc = this[index1]; + this[index1] = this[index2]; + this[index2] = dc; + } + } + + } +} diff --git a/Greenshot/Drawing/EllipseContainer.cs b/Greenshot/Drawing/EllipseContainer.cs new file mode 100644 index 000000000..4711e6853 --- /dev/null +++ b/Greenshot/Drawing/EllipseContainer.cs @@ -0,0 +1,92 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of EllipseContainer. + /// + [Serializable()] + public class EllipseContainer : DrawableContainer { + + public EllipseContainer(Surface parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.LINE_THICKNESS)); + AddField(FieldFactory.CreateField(FieldType.LINE_COLOR)); + AddField(FieldFactory.CreateField(FieldType.FILL_COLOR)); + AddField(FieldFactory.CreateField(FieldType.SHADOW)); + } + + public override void Draw(Graphics graphics, RenderMode renderMode) { + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.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))) { + shadowPen.Width = lineVisible ? lineThickness : 1; + Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height); + graphics.DrawEllipse(shadowPen, shadowRect); + currentStep++; + alpha = alpha - basealpha / steps; + } + } + } + + //draw the original shape + Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); + + using (Brush brush = new SolidBrush(fillColor)) { + graphics.FillEllipse(brush, rect); + } + + using (Pen pen = new Pen(lineColor)) { + pen.Width = lineThickness; + if (pen.Width > 0) { + graphics.DrawEllipse(pen, rect); + } + } + } + + public override bool Contains(int x, int y) { + double xDistanceFromCenter = x - (Left+Width/2); + double yDistanceFromCenter = y - (Top+Height/2); + // ellipse: x^2/a^2 + y^2/b^2 = 1 + return Math.Pow(xDistanceFromCenter,2)/Math.Pow(Width/2,2) + Math.Pow(yDistanceFromCenter,2)/Math.Pow(Height/2,2) < 1; + } + } +} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs new file mode 100644 index 000000000..dd5cac654 --- /dev/null +++ b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs @@ -0,0 +1,153 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Reflection; +using System.Runtime.Serialization; + +using Greenshot.Helpers; + +namespace Greenshot.Drawing.Fields { + /// + /// Basic IFieldHolder implementation, providing access to a set of fields + /// + [Serializable()] + public abstract class AbstractFieldHolder : IFieldHolder { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(AbstractFieldHolder)); + + /// + /// called when a field's value has changed + /// + [NonSerialized] + private FieldChangedEventHandler fieldChanged; + public event FieldChangedEventHandler FieldChanged { + add { fieldChanged += value; } + remove{ fieldChanged -= value; } + } + + // we keep to Coolections of our fields, dictionary for quick access, list for serialization + // this allows us to use default serialization + [NonSerialized] + private Dictionary fieldsByType = new Dictionary(); + private List fields = new List(); + + + + + public AbstractFieldHolder() {} + + [OnDeserializedAttribute()] + private void OnDeserialized(StreamingContext context) { + fieldsByType = new Dictionary(); + // listen to changing properties + foreach(Field field in fields) { + field.PropertyChanged += delegate { if(fieldChanged != null) fieldChanged(this, new FieldChangedEventArgs(field)); }; + fieldsByType[field.FieldType] = field; + } + } + + public virtual void AddField(Field field) { + if(fieldsByType != null && fieldsByType.ContainsKey(field.FieldType)) { + if(LOG.IsDebugEnabled) LOG.Debug("A field with of type '"+field.FieldType+"' already exists in this "+GetType()+", will overwrite."); + } + + fields.Add(field); + fieldsByType[field.FieldType] = field; + field.PropertyChanged += delegate { if(fieldChanged != null) fieldChanged(this, new FieldChangedEventArgs(field)); }; + } + + public void RemoveField(Field field) { + fields.Remove(field); + fieldsByType.Remove(field.FieldType); + field.PropertyChanged -= delegate { if(fieldChanged != null) fieldChanged(this, new FieldChangedEventArgs(field)); }; + } + + public List GetFields() { + return fields; + } + + + public Field GetField(FieldType fieldType) { + try { + return fieldsByType[fieldType]; + } catch(KeyNotFoundException e) { + throw new ArgumentException("Field '"+fieldType+"' does not exist in " + GetType(), e); + } + } + + public object GetFieldValue(FieldType fieldType) { + return GetField(fieldType).Value; + } + + #region convenience methods to save us some casts outside + public string GetFieldValueAsString(FieldType fieldType) { + return (string)GetFieldValue(fieldType); + } + + public int GetFieldValueAsInt(FieldType fieldType) { + return (int)GetFieldValue(fieldType); + } + + public decimal GetFieldValueAsDecimal(FieldType fieldType) { + return (decimal)GetFieldValue(fieldType); + } + + public double GetFieldValueAsDouble(FieldType fieldType) { + return (double)GetFieldValue(fieldType); + } + + public float GetFieldValueAsFloat(FieldType fieldType) { + return (float)GetFieldValue(fieldType); + } + + public bool GetFieldValueAsBool(FieldType fieldType) { + return (bool)GetFieldValue(fieldType); + } + + public Color GetFieldValueAsColor(FieldType fieldType) { + return (Color)GetFieldValue(fieldType); + } + #endregion + + public bool HasField(FieldType fieldType) { + return fieldsByType.ContainsKey(fieldType); + } + + public bool HasFieldValue(FieldType fieldType) { + return HasField(fieldType) && fieldsByType[fieldType].HasValue; + } + + public void SetFieldValue(FieldType 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){ + if(fieldChanged != null) fieldChanged(sender, e); + } + + } +} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs new file mode 100644 index 000000000..8254ed35e --- /dev/null +++ b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs @@ -0,0 +1,126 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Reflection; +using System.Runtime.Serialization; + +using Greenshot.Helpers; + +namespace Greenshot.Drawing.Fields { + /// + /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, + /// but has a List of children. + /// Field values are passed to and from children as well. + /// + [Serializable()] + public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder { + + FieldChangedEventHandler fieldChangedEventHandler; + + [NonSerialized] + private EventHandler childrenChanged; + public event EventHandler ChildrenChanged { + add { childrenChanged += value; } + remove { childrenChanged -= value; } + } + + public List Children = new List(); + + public AbstractFieldHolderWithChildren() { + fieldChangedEventHandler = new FieldChangedEventHandler(OnFieldChanged); + } + + [OnDeserializedAttribute()] + private void OnDeserialized(StreamingContext context) { + // listen to changing properties + foreach(IFieldHolder fieldHolder in Children) { + fieldHolder.FieldChanged += fieldChangedEventHandler; + } + if(childrenChanged != null) childrenChanged(this, EventArgs.Empty); + } + + public void AddChild(IFieldHolder fieldHolder) { + Children.Add(fieldHolder); + fieldHolder.FieldChanged += fieldChangedEventHandler; + if(childrenChanged != null) childrenChanged(this, EventArgs.Empty); + } + + public void RemoveChild(IFieldHolder fieldHolder) { + Children.Remove(fieldHolder); + fieldHolder.FieldChanged -= fieldChangedEventHandler; + if(childrenChanged != null) childrenChanged(this, EventArgs.Empty); + } + + public new List GetFields() { + List ret = new List(); + ret.AddRange(base.GetFields()); + foreach(IFieldHolder fh in Children) { + ret.AddRange(fh.GetFields()); + } + return ret; + } + + public new Field GetField(FieldType fieldType) { + Field 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(FieldType 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(FieldType fieldType) { + Field f = GetField(fieldType); + return f != null && f.HasValue; + } + + public new void SetFieldValue(FieldType fieldType, object value) { + Field 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 new file mode 100644 index 000000000..0454450c3 --- /dev/null +++ b/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs @@ -0,0 +1,47 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +namespace Greenshot.Drawing.Fields.Binding { + /// + /// Basic IBindingConverter implementation + /// + public abstract class AbstractBindingConverter : IBindingConverter + { + public AbstractBindingConverter() {} + + public object convert(object o) { + if(o == null) { + return null; + } else if(o is T1) { + return convert((T1)o); + } else if(o is T2) { + return convert((T2)o); + } else { + 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 new file mode 100644 index 000000000..2175a7a4b --- /dev/null +++ b/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs @@ -0,0 +1,168 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +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 INotifyPropertyChanged object1; + private INotifyPropertyChanged object2; + private string property1; + private string property2; + private bool updatingObject1 = false; + private bool updatingObject2 = false; + private IBindingConverter converter; + private 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 object1, string property1, INotifyPropertyChanged object2, string property2) + { + this.object1 = object1; + this.object2 = object2; + this.property1 = property1; + this.property2 = property2; + + this.object1.PropertyChanged += new PropertyChangedEventHandler(Property1Changed); + this.object2.PropertyChanged += new PropertyChangedEventHandler(Property2Changed); + } + + /// + /// 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 synchronzied value to the correct target format and back + public BidirectionalBinding(INotifyPropertyChanged object1, string property1, INotifyPropertyChanged object2, string property2, IBindingConverter converter) : this(object1, property1, object2, property2) + { + this.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 synchronisation if the value does not match certain criteria + public BidirectionalBinding(INotifyPropertyChanged object1, string property1, INotifyPropertyChanged object2, string property2, IBindingValidator validator) : this(object1, property1, object2, property2) + { + this.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 synchronzied value to the correct target format and back + /// validator to intercept synchronisation if the value does not match certain criteria + public BidirectionalBinding(INotifyPropertyChanged object1, string property1, INotifyPropertyChanged object2, string property2, IBindingConverter converter, IBindingValidator validator) : this(object1, property1, object2, property2, converter) + { + this.validator = validator; + } + + public void Property1Changed(object sender, PropertyChangedEventArgs e) + { + if(!updatingObject1 && e.PropertyName.Equals(property1)) + { + updatingObject2 = true; + synchronize(object1, property1, object2, property2); + updatingObject2 = false; + } + } + + public void Property2Changed(object sender, PropertyChangedEventArgs e) + { + if(!updatingObject2 && e.PropertyName.Equals(property2)) + { + updatingObject1 = true; + synchronize(object2, property2, object1, property1); + updatingObject1 = 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!=null)?bValue.GetType().Name:"")+"] on "+targetObject+". Probably other type than expected, IBindingCoverter to the rescue.", e); + } + + } + } + + private 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 double (%) and vice versa, e.g. 95f <---> 0.95d + /// + public class DecimalDoublePercentageConverter : AbstractBindingConverter + { + private static DecimalDoublePercentageConverter uniqueInstance; + + private DecimalDoublePercentageConverter() {} + + protected override decimal convert(double o) { + return Convert.ToDecimal(o)*100; + } + + protected override double convert(decimal o) { + return Convert.ToDouble(o)/100; + } + + public static DecimalDoublePercentageConverter GetInstance() { + if(uniqueInstance == null) uniqueInstance = new DecimalDoublePercentageConverter(); + return uniqueInstance; + } + + } +} diff --git a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs new file mode 100644 index 000000000..74e9cc4b7 --- /dev/null +++ b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs @@ -0,0 +1,47 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +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.ToInt16(o); + } + + public static DecimalFloatConverter GetInstance() { + if(uniqueInstance == null) uniqueInstance = new DecimalFloatConverter(); + return uniqueInstance; + } + + } +} diff --git a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs new file mode 100644 index 000000000..fe5d4f586 --- /dev/null +++ b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs @@ -0,0 +1,47 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +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.ToInt16(o); + } + + public static DecimalIntConverter GetInstance() { + if(uniqueInstance == null) uniqueInstance = new DecimalIntConverter(); + return uniqueInstance; + } + + } +} diff --git a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs b/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs new file mode 100644 index 000000000..e2cfc3369 --- /dev/null +++ b/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs @@ -0,0 +1,34 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +namespace Greenshot.Drawing.Fields.Binding { + + /// + /// Interface for a bidirectional converter, for use with BidirectionalBinding. + /// convert(object) implementation must deal with both directions. + /// see DecimalIntConverter + /// + public interface IBindingConverter { + object convert(object o); + } + +} diff --git a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs new file mode 100644 index 000000000..5d568ca49 --- /dev/null +++ b/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs @@ -0,0 +1,35 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +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/Binding/NotNullValidator.cs b/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs new file mode 100644 index 000000000..1a67621aa --- /dev/null +++ b/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs @@ -0,0 +1,42 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; + +namespace Greenshot.Drawing.Fields.Binding { + /// + /// Validates a value not to be null. + /// + public class NotNullValidator : IBindingValidator { + private static NotNullValidator uniqueInstance; + + private NotNullValidator() { + } + + public bool validate(object o) { + return o != null; + } + + public static NotNullValidator GetInstance() { + if(uniqueInstance == null) uniqueInstance = new NotNullValidator(); + return uniqueInstance; + } + } +} diff --git a/Greenshot/Drawing/Fields/Field.cs b/Greenshot/Drawing/Fields/Field.cs new file mode 100644 index 000000000..1b05b9143 --- /dev/null +++ b/Greenshot/Drawing/Fields/Field.cs @@ -0,0 +1,122 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +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 : INotifyPropertyChanged { + [field:NonSerialized] + public event PropertyChangedEventHandler PropertyChanged; + + public object myValue; + public object Value { + get { return myValue; } + set { if(!object.Equals(myValue,value)) { + myValue = value; + if(PropertyChanged!=null) PropertyChanged(this, new PropertyChangedEventArgs("Value")); } + } + } + public FieldType FieldType; + public string Scope; + + /// + /// 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(FieldType fieldType, Type scope) { + FieldType = fieldType; + Scope = scope.FullName; + } + public Field(FieldType fieldType, string scope) { + FieldType = fieldType; + Scope = scope; + } + public Field(FieldType fieldType) { + FieldType = fieldType; + } + /// + /// Returns true if this field holds a value other than null. + /// + public bool HasValue { + get{ return Value != null; } + } + + /// + /// Creates a flat clone of this Field. The fields value itself is not cloned. + /// + /// + public Field Clone() { + Field ret = new Field(FieldType, Scope); + ret.Value = Value; + return ret; + } + + 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) { + Field other = obj as Field; + if (other == null) { + return false; + } + return this.FieldType == other.FieldType && object.Equals(this.Scope, other.Scope); + } + + public override string ToString() { + return string.Format("[Field FieldType={1} Value={0} Scope={2}]", this.myValue, this.FieldType, this.Scope); + } + } + + + /// + /// EventHandler to be used when a field value changes + /// + public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); + + /// + /// EventArgs to be used with FieldChangedEventHandler + /// + public class FieldChangedEventArgs : EventArgs { + public readonly Field Field; + public FieldChangedEventArgs(Field field) { + this.Field = field; + } + } +} diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs new file mode 100644 index 000000000..5bd8e8a7e --- /dev/null +++ b/Greenshot/Drawing/Fields/FieldAggregator.cs @@ -0,0 +1,186 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Reflection; +using System.ComponentModel; +using System.Collections.Generic; +using Greenshot.Configuration; +using Greenshot.Drawing.Filters; +using Greenshot.Helpers; + +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. + /// + public class FieldAggregator : AbstractFieldHolder { + + private List boundContainers; + private bool internalUpdateRunning = false; + + enum Status {IDLE, BINDING, UPDATING}; + + private Status status; + + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FieldAggregator)); + + public FieldAggregator() { + List fields = FieldFactory.GetDefaultFields(); + foreach(Field field in fields) { + AddField(field); + } + boundContainers = new List(); + } + + + public override void AddField(Field field) { + base.AddField(field); + field.PropertyChanged += new PropertyChangedEventHandler(OwnPropertyChanged); + } + + public void BindElements(DrawableContainerList dcs) { + foreach(DrawableContainer dc in dcs) { + BindElement(dc); + } + } + public void BindElement(DrawableContainer dc) { + status = Status.BINDING; + if(LOG.IsDebugEnabled) LOG.Debug("Binding element of type "+dc.GetType()); + if(!boundContainers.Contains(dc)) { + boundContainers.Add(dc); + status = Status.IDLE; + dc.ChildrenChanged += delegate { UpdateFromBoundElements(); }; + UpdateFromBoundElements(); + } + } + + public void BindAndUpdateElement(DrawableContainer dc) { + UpdateElement(dc); + BindElement(dc); + } + + public void UpdateElement(DrawableContainer dc) { + if(LOG.IsDebugEnabled) LOG.Debug("Updating element of type "+dc.GetType()); + internalUpdateRunning = true; + foreach(Field field in GetFields()) { + if(dc.HasField(field.FieldType) && field.HasValue) { + //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value); + dc.SetFieldValue(field.FieldType, field.Value); + } + } + internalUpdateRunning = false; + } + + public void UnbindElement(DrawableContainer dc) { + if(boundContainers.Contains(dc)) { + if(LOG.IsDebugEnabled) LOG.Debug("Unbinding element of type "+dc.GetType()); + 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; + //if(LOG.IsDebugEnabled) LOG.Debug("Clearing fields internally"); + foreach(Field field in GetFields()) { + field.Value = null; + //if(LOG.IsDebugEnabled) LOG.Debug(" "+field.GetType()+ ": "+field.Value); + } + 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() { + if(LOG.IsDebugEnabled) LOG.Debug("Updating from bound elements, status = "+status); + status = Status.UPDATING; + ClearFields(); + internalUpdateRunning = true; + foreach(Field f in FindCommonFields()) { + SetFieldValue(f.FieldType,f.Value); + //if(LOG.IsDebugEnabled) LOG.Debug("Updating own field: "+f.FieldType+": "+GetField(f.FieldType).Value); + } + internalUpdateRunning = false; + status = Status.IDLE; + } + + private List FindCommonFields() { + List ret = null; + if(boundContainers.Count > 0) { + // take all fields from the least selected container... + ret = boundContainers[boundContainers.Count-1].GetFields(); + for(int i=0;i fieldsToRemove = new List(); + foreach(Field f in ret) { + // ... throw out those that do not apply to one of the other containers + if(!dc.HasField(f.FieldType)) fieldsToRemove.Add(f); + } + foreach(Field f in fieldsToRemove) { + ret.Remove(f); + } + } + } + if(ret == null) ret = new List(); + return ret; + } + + public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) { + Field f = (Field) sender; + if(!internalUpdateRunning && f.Value!=null) { + + foreach(DrawableContainer dc in boundContainers) { + if(f.Scope == null || dc.GetType().FullName.Equals(f.Scope)) { + if(LOG.IsDebugEnabled) LOG.Debug("Updating field: "+f.FieldType+": "+f.Value); + if(dc.HasField(f.FieldType)) { + Field dcf = dc.GetField(f.FieldType); + dcf.Value = f.Value; + // update last used from DC field, so that scope is honored + AppConfig.GetInstance().UpdateLastUsedFieldValue(dcf); + } + + } + } + } + } + + } +} diff --git a/Greenshot/Drawing/Fields/FieldFactory.cs b/Greenshot/Drawing/Fields/FieldFactory.cs new file mode 100644 index 000000000..92e195382 --- /dev/null +++ b/Greenshot/Drawing/Fields/FieldFactory.cs @@ -0,0 +1,92 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Collections.Generic; +using Greenshot.Configuration; + +namespace Greenshot.Drawing.Fields { + + /// + /// In charge for creating Fields for DrawableContainers or Filters. + /// Add new FieldTypes in FieldType.cs + /// + public class FieldFactory { + + private FieldFactory() {} + + /// FieldType of the field to construct + /// a new Field of the given fieldType + public static Field CreateField(FieldType fieldType) { + return CreateField(fieldType, null, null); + } + + /// FieldType of the field to construct + /// overwrites the original default value being defined in FieldType + /// a new Field of the given fieldType and initialValue + public static Field CreateField(FieldType fieldType, object preferredDefaultValue) { + return CreateField(fieldType, null, preferredDefaultValue); + } + + /// FieldType of the field to construct + /// the value to be inserted, regardless of last used value or default value for this field + /// a new Field of the given fieldType and initialValue + public static Field CreateFieldWithValue(FieldType fieldType, object forcedValue) { + Field ret = new Field(fieldType); + ret.Value = forcedValue; + return ret; + + } + + /// FieldType of the field to construct + /// 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 static Field CreateField(FieldType fieldType, Type scope) { + return CreateField(fieldType, scope, null); + } + + /// FieldType of the field to construct + /// overwrites the original default value being defined in FieldType + /// a new Field of the given fieldType and preferredDefaultValue, with the scope of it's value being restricted to the Type scope + public static Field CreateField(FieldType fieldType, Type scope, object preferredDefaultValue) { + Field ret = null; + if (scope != null) { + ret = new Field(fieldType, scope); + } else { + ret = new Field(fieldType); + } + AppConfig.GetInstance().GetLastUsedValueForField(ret, preferredDefaultValue); + return ret; + } + + /// a List of all available fields with their respective default value + public static List GetDefaultFields() { + List ret = new List(); + foreach(FieldType ft in FieldType.Values) { + Field f = CreateField(ft); + f.Value = ft.DefaultValue; + ret.Add(f); + } + return ret; + } + } + +} diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/Greenshot/Drawing/Fields/FieldType.cs new file mode 100644 index 000000000..d0c404532 --- /dev/null +++ b/Greenshot/Drawing/Fields/FieldType.cs @@ -0,0 +1,117 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; + +namespace Greenshot.Drawing.Fields { + /// + /// Defines all FieldTypes + their default value. + /// (The additional value is why this is not an enum) + /// + [Serializable] + public class FieldType { + + public static readonly FieldType ARROWHEADS = new FieldType("ARROWHEADS", Greenshot.Drawing.ArrowContainer.ArrowHeadCombination.END_POINT); + public static readonly FieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS", 3); + public static readonly FieldType BRIGHTNESS = new FieldType("BRIGHTNESS", 0.9d); + public static readonly FieldType FILL_COLOR = new FieldType("FILL_COLOR", Color.Transparent); + public static readonly FieldType FONT_BOLD = new FieldType("FONT_BOLD", false); + public static readonly FieldType FONT_FAMILY = new FieldType("FONT_FAMILY", FontFamily.GenericSansSerif.Name); + public static readonly FieldType FONT_ITALIC = new FieldType("FONT_ITALIC", false); + public static readonly FieldType FONT_SIZE = new FieldType("FONT_SIZE", 11f); + public static readonly FieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR", Color.Yellow); + public static readonly FieldType LINE_COLOR = new FieldType("LINE_COLOR", Color.Red); + public static readonly FieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS", 1); + public static readonly FieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR", 2); + public static readonly FieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE", 5); + public static readonly FieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY", 1.0d); + public static readonly FieldType SHADOW = new FieldType("SHADOW", false); + public static readonly FieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE", FilterContainer.PreparedFilter.PIXELIZE); + public static readonly FieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT", FilterContainer.PreparedFilter.TEXT_HIGHTLIGHT); + public static readonly FieldType FLAGS = new FieldType("FLAGS", null); + + public static FieldType[] Values = new FieldType[]{ + ARROWHEADS, + BLUR_RADIUS, + BRIGHTNESS, + FILL_COLOR, + FONT_BOLD, + FONT_FAMILY, + FONT_ITALIC, + FONT_SIZE, + HIGHLIGHT_COLOR, + LINE_COLOR, + LINE_THICKNESS, + MAGNIFICATION_FACTOR, + PIXEL_SIZE, + PREVIEW_QUALITY, + SHADOW, + PREPARED_FILTER_OBFUSCATE, + PREPARED_FILTER_HIGHLIGHT, + FLAGS + }; + + [Flags] + public enum Flag { + NONE = 0, + CONFIRMABLE = 1 + } + + + public object DefaultValue; + public string Name; + private FieldType(string name, object defaultValue) { + Name = name; + DefaultValue=defaultValue; + } + public override string ToString() { + return this.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 object.Equals(this.Name,other.Name); + } + + public static bool operator ==(FieldType a, FieldType b) { + return object.Equals(a,b); + } + + public static bool operator !=(FieldType a, FieldType b) { + return !object.Equals(a,b); + } + + } + + +} diff --git a/Greenshot/Drawing/Fields/IFieldHolder.cs b/Greenshot/Drawing/Fields/IFieldHolder.cs new file mode 100644 index 000000000..4a2050b93 --- /dev/null +++ b/Greenshot/Drawing/Fields/IFieldHolder.cs @@ -0,0 +1,53 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; + +namespace Greenshot.Drawing.Fields { + /// + /// Any element holding Fields must provide access to it. + /// AbstractFieldHolder is the basic implementation. + /// If you need the fieldHolder to have child fieldHolders, + /// you should consider using IFieldHolderWithChildren. + /// + public interface IFieldHolder { + + event FieldChangedEventHandler FieldChanged; + + void AddField(Field field); + void RemoveField(Field field); + List GetFields(); + Field GetField(FieldType fieldType); + bool HasField(FieldType fieldType); + void SetFieldValue(FieldType fieldType, object value); + } + + /// + /// Extended fieldHolder which has fieldHolder children. + /// Implementations should pass field values to and from + /// their children. + /// AbstractFieldHolderWithChildren is the basic implementation. + /// + public interface IFieldHolderWithChildren : IFieldHolder { + void AddChild(IFieldHolder fieldHolder); + void RemoveChild(IFieldHolder fieldHolder); + } +} diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs new file mode 100644 index 000000000..acd472bd2 --- /dev/null +++ b/Greenshot/Drawing/FilterContainer.cs @@ -0,0 +1,90 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// empty container for filter-only elements + /// + [Serializable()] + public class FilterContainer : DrawableContainer { + + public enum PreparedFilterMode {OBFUSCATE, HIGHLIGHT}; + public enum PreparedFilter {BLUR, PIXELIZE, TEXT_HIGHTLIGHT, AREA_HIGHLIGHT, GRAYSCALE, MAGNIFICATION}; + + public PreparedFilter Filter { + get { return (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); } + } + + public FilterContainer(Surface parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.LINE_THICKNESS, GetType())); + AddField(FieldFactory.CreateField(FieldType.LINE_COLOR, GetType())); + AddField(FieldFactory.CreateField(FieldType.SHADOW)); + } + + public override void Draw(Graphics g, 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 (shadow && lineVisible) { + //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))) { + shadowPen.Width = lineVisible ? lineThickness : 1; + Rectangle shadowRect = GuiRectangle.GetGuiRectangle( + this.Left + currentStep, + this.Top + currentStep, + this.Width, + this.Height); + g.DrawRectangle(shadowPen, shadowRect); + currentStep++; + alpha = alpha - (basealpha / steps); + } + } + } + + Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); + + using (Pen pen = new Pen(lineColor)) { + pen.Width = lineThickness; + if(pen.Width > 0) { + g.DrawRectangle(pen, rect); + } + } + + } + } +} diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs new file mode 100644 index 000000000..cea7224b8 --- /dev/null +++ b/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -0,0 +1,121 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.Serialization; + +using Greenshot.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Plugin.Drawing; + +/// +/// Graphical filter which can be added to DrawableContainer. +/// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call +/// OnPropertyChanged whenever a public property has been changed. +/// +namespace Greenshot.Drawing.Filters { + [Serializable()] + public abstract class AbstractFilter : AbstractFieldHolder, IFilter { + + [NonSerialized] + private PropertyChangedEventHandler propertyChanged; + public event PropertyChangedEventHandler PropertyChanged { + add { propertyChanged += value; } + remove{ propertyChanged -= value; } + } + + private bool invert = false; + public bool Invert { + get { return invert; } + set { invert=value; OnPropertyChanged("Invert"); } + } + protected BitmapBuffer bbb; + protected Rectangle applyRect; + protected DrawableContainer parent; + public DrawableContainer Parent { + get {return parent;} + set {parent = value;} + } + + public AbstractFilter(DrawableContainer parent) { + this.parent = parent; + } + + public DrawableContainer GetParent() { + return parent; + } + + /** + * This method fixes the problem that we can't apply a filter outside the target bitmap, + * therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap. + * It will also account for the Invert flag. + */ + protected Rectangle IntersectRectangle(Size applySize, Rectangle rect) { + Rectangle myRect; + if (Invert) { + myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + } else { + Rectangle applyRect = new Rectangle(0,0, applySize.Width, applySize.Height); + myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); + myRect.Intersect(applyRect); + } + return myRect; + } + + public virtual void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { + applyRect = IntersectRectangle(applyBitmap.Size, rect); + + if (applyRect.Width == 0 || applyRect.Height == 0) { + // nothing to do + return; + } + + bbb = new BitmapBuffer(applyBitmap, applyRect); + try { + bbb.Lock(); + for(int y=0;y +/// Parts of this class were taken from BlurEffect.cs of Paint.NET 3.0.1, +/// which was released under MIT license. +/// http://www.getpaint.net +/// Some of this code has been adapted for integration with Greenshot. +/// See Paint.NET copyright notice below. +/// + +///////////////////////////////////////////////////////////////////////////////// +// Paint.NET // +// Copyright (C) Rick Brewster, Tom Jackson, and past contributors. // +// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // +// See src/Resources/Files/License.txt for full licensing and attribution // +// details. // +// . // +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; +using Greenshot.Plugin.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(FieldFactory.CreateField(FieldType.BLUR_RADIUS, GetType())); + AddField(FieldFactory.CreateField(FieldType.PREVIEW_QUALITY)); + } + + public static int[] CreateGaussianBlurRow(int amount) { + int size = 1 + (amount * 2); + int[] weights = new int[size]; + + for (int i = 0; i <= amount; ++i) + { + // 1 + aa - aa + 2ai - ii + weights[i] = 16 * (i + 1); + weights[weights.Length - i - 1] = weights[i]; + } + + return weights; + } + + public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { + applyRect = IntersectRectangle(applyBitmap.Size, rect); + + if (applyRect.Height <= 0 || applyRect.Width <= 0) { + return; + } + + int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); + double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY); + + // do nothing when nothing can be done! + if (blurRadius < 1) { + return; + } + + using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, applyRect)) { + bbbDest.Lock(); + using (BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, applyRect)) { + bbbSrc.Lock(); + Random rand = new Random(); + + int r = blurRadius; + int[] w = CreateGaussianBlurRow(r); + int wlen = w.Length; + + for (int y = 0; y < applyRect.Height; ++y) { + long* waSums = stackalloc long[wlen]; + long* wcSums = stackalloc long[wlen]; + long* aSums = stackalloc long[wlen]; + long* bSums = stackalloc long[wlen]; + long* gSums = stackalloc long[wlen]; + long* rSums = stackalloc long[wlen]; + long waSum = 0; + long wcSum = 0; + long aSum = 0; + long bSum = 0; + long gSum = 0; + long rSum = 0; + + for (int wx = 0; wx < wlen; ++wx) { + int srcX = wx - r; + waSums[wx] = 0; + wcSums[wx] = 0; + aSums[wx] = 0; + bSums[wx] = 0; + gSums[wx] = 0; + rSums[wx] = 0; + + if (srcX >= 0 && srcX < bbbDest.Width) { + for (int wy = 0; wy < wlen; ++wy) { + int srcY = y + wy - r; + + if (srcY >= 0 && srcY < bbbDest.Height) { + int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); + int wp = w[wy]; + + waSums[wx] += wp; + wp *= colors[0] + (colors[0] >> 7); + wcSums[wx] += wp; + wp >>= 8; + + aSums[wx] += wp * colors[0]; + bSums[wx] += wp * colors[3]; + gSums[wx] += wp * colors[2]; + rSums[wx] += wp * colors[1]; + } + } + + int wwx = w[wx]; + waSum += wwx * waSums[wx]; + wcSum += wwx * wcSums[wx]; + aSum += wwx * aSums[wx]; + bSum += wwx * bSums[wx]; + gSum += wwx * gSums[wx]; + rSum += wwx * rSums[wx]; + } + } + + wcSum >>= 8; + + if (waSum == 0 || wcSum == 0) { + SetColorAt(bbbDest, 0, y, new int[]{0,0,0,0}); + } else { + int alpha = (int)(aSum / waSum); + int blue = (int)(bSum / wcSum); + int green = (int)(gSum / wcSum); + int red = (int)(rSum / wcSum); + + SetColorAt(bbbDest, 0, y, new int[]{alpha, red, green, blue}); + } + + for (int x = 1; x < applyRect.Width; ++x) { + for (int i = 0; i < wlen - 1; ++i) { + waSums[i] = waSums[i + 1]; + wcSums[i] = wcSums[i + 1]; + aSums[i] = aSums[i + 1]; + bSums[i] = bSums[i + 1]; + gSums[i] = gSums[i + 1]; + rSums[i] = rSums[i + 1]; + } + + waSum = 0; + wcSum = 0; + aSum = 0; + bSum = 0; + gSum = 0; + rSum = 0; + + int wx; + for (wx = 0; wx < wlen - 1; ++wx) { + long wwx = (long)w[wx]; + waSum += wwx * waSums[wx]; + wcSum += wwx * wcSums[wx]; + aSum += wwx * aSums[wx]; + bSum += wwx * bSums[wx]; + gSum += wwx * gSums[wx]; + rSum += wwx * rSums[wx]; + } + + wx = wlen - 1; + + waSums[wx] = 0; + wcSums[wx] = 0; + aSums[wx] = 0; + bSums[wx] = 0; + gSums[wx] = 0; + rSums[wx] = 0; + + int srcX = x + wx - r; + + if (srcX >= 0 && srcX < applyRect.Width) { + for (int wy = 0; wy < wlen; ++wy) { + int srcY = y + wy - r; + // only when in EDIT mode, ignore some pixels depending on preview quality + if ((renderMode==RenderMode.EXPORT || rand.NextDouble()= 0 && srcY < applyRect.Height) { + int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); + int wp = w[wy]; + + waSums[wx] += wp; + wp *= colors[0] + (colors[0] >> 7); + wcSums[wx] += wp; + wp >>= 8; + + aSums[wx] += wp * (long)colors[0]; + bSums[wx] += wp * (long)colors[3]; + gSums[wx] += wp * (long)colors[2]; + rSums[wx] += wp * (long)colors[1]; + } + } + + int wr = w[wx]; + waSum += (long)wr * waSums[wx]; + wcSum += (long)wr * wcSums[wx]; + aSum += (long)wr * aSums[wx]; + bSum += (long)wr * bSums[wx]; + gSum += (long)wr * gSums[wx]; + rSum += (long)wr * rSums[wx]; + } + + wcSum >>= 8; + + if (waSum == 0 || wcSum == 0) { + SetColorAt(bbbDest, x, y, new int[]{0,0,0,0}); + } else { + int alpha = (int)(aSum / waSum); + int blue = (int)(bSum / wcSum); + int green = (int)(gSum / wcSum); + int red = (int)(rSum / wcSum); + + SetColorAt(bbbDest, x, y, new int[]{alpha, red, green, blue}); + } + } + } + } + bbbDest.DrawTo(graphics, applyRect.Location); + } + } + + private void SetColorAt(BitmapBuffer bbb, int x, int y, int[] colors) { + if(parent.Contains(applyRect.Left+x, applyRect.Top+y) ^ Invert) { + bbb.SetColorArrayAt(x, y, colors); + } + } + } +} diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/Greenshot/Drawing/Filters/BrightnessFilter.cs new file mode 100644 index 000000000..383ba55b7 --- /dev/null +++ b/Greenshot/Drawing/Filters/BrightnessFilter.cs @@ -0,0 +1,56 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.Serialization; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing.Filters { + [Serializable()] + public class BrightnessFilter : AbstractFilter { + + private double brightness; + + public BrightnessFilter(DrawableContainer parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.BRIGHTNESS, GetType())); + } + + protected override void IteratePixel(int x, int y) { + Color color = bbb.GetColorAt(x, y); + int r = Convert.ToInt16(color.R*brightness); + int g = Convert.ToInt16(color.G*brightness); + int b = Convert.ToInt16(color.B*brightness); + r = (r>255) ? 255 : r; + g = (g>255) ? 255 : g; + b = (b>255) ? 255 : b; + bbb.SetColorAt(x, y, Color.FromArgb(color.A, r, g, b)); + } + + public override void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode) { + brightness = GetFieldValueAsDouble(FieldType.BRIGHTNESS); + base.Apply(graphics, bmp, rect, renderMode); + } + } +} diff --git a/Greenshot/Drawing/Filters/FastSmoothFilter.cs b/Greenshot/Drawing/Filters/FastSmoothFilter.cs new file mode 100644 index 000000000..6db3372fc --- /dev/null +++ b/Greenshot/Drawing/Filters/FastSmoothFilter.cs @@ -0,0 +1,231 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.Serialization; + +using Greenshot.Drawing.Fields; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing.Filters { + [Serializable()] + public class FastSmoothFilter : AbstractFilter { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastSmoothFilter)); + + public FastSmoothFilter(DrawableContainer parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.BLUR_RADIUS, GetType())); + } + + public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle applyRect, RenderMode renderMode) { + Rectangle sourceRect = new Rectangle(applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height); + Rectangle bitmapRect = new Rectangle(0,0, applyBitmap.Width, applyBitmap.Height); + + if(sourceRect.Equals(Rectangle.Empty)) { + sourceRect = bitmapRect; + } else { + sourceRect.Intersect(bitmapRect); + } + // Does the rect have any pixels? + if (sourceRect.Height <= 0 || sourceRect.Width <= 0) { + return; + } + + int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); + + // Calculate new sourceRect to include the matrix size if possible + + int leftOffset = Math.Min(sourceRect.X, blurRadius); + int rightOffset = Math.Min(applyBitmap.Width - (sourceRect.X + sourceRect.Width), blurRadius); + int topOffset = Math.Min(sourceRect.Y, blurRadius); + int bottomOffset = Math.Min(applyBitmap.Height - (sourceRect.Y + sourceRect.Height), blurRadius); + LOG.Debug(String.Format("Offsets: {0},{1},{2},{3}", leftOffset, rightOffset, topOffset, bottomOffset)); + LOG.Debug(String.Format("SourceRect before: {0},{1},{2},{3}", sourceRect.X, sourceRect.Width, sourceRect.Y, sourceRect.Height)); + sourceRect.X -= leftOffset; + sourceRect.Width += leftOffset + rightOffset; + sourceRect.Y -= topOffset; + sourceRect.Height += topOffset + bottomOffset; + LOG.Debug(String.Format("SourceRect after: {0},{1},{2},{3}", sourceRect.X, sourceRect.Width, sourceRect.Y, sourceRect.Height)); + // Make a copy of the applyBitmap for reading + + using (Bitmap sourceBitmap = applyBitmap.Clone(sourceRect, applyBitmap.PixelFormat)) { + ApplySmooth(sourceBitmap, applyBitmap, sourceRect, blurRadius); + } + } + + public static bool ApplySmooth(Bitmap sourceBitmap, Bitmap destinationBitmap, Rectangle destRectangle, int blurRadius) { + if (blurRadius < 1) { + return false; + } + + BitmapData destbitmapData = destinationBitmap.LockBits(destRectangle, ImageLockMode.WriteOnly, destinationBitmap.PixelFormat); + BitmapData srcBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), + ImageLockMode.ReadOnly, + sourceBitmap.PixelFormat); + + int destStride = destbitmapData.Stride; + int srcStride = srcBitmapData.Stride; + + IntPtr destScan0 = destbitmapData.Scan0; + IntPtr srcScan0 = srcBitmapData.Scan0; + + int bIndex; + int gIndex; + int rIndex; + //int aIndex; + int bytesPerPixel; + switch(destinationBitmap.PixelFormat) { + case PixelFormat.Format32bppArgb: + // GDI+ lies to us - the return format is BGR, NOT RGB. + bIndex = 0; + gIndex = 1; + rIndex = 2; + //aIndex = 3; + bytesPerPixel = 4; + break; + case PixelFormat.Format32bppRgb: + // GDI+ lies to us - the return format is BGR, NOT RGB. + bIndex = 0; + gIndex = 1; + rIndex = 2; + bytesPerPixel = 4; + break; + case PixelFormat.Format24bppRgb: + // GDI+ lies to us - the return format is BGR, NOT RGB. + bIndex = 0; + gIndex = 1; + rIndex = 2; + bytesPerPixel = 3; + break; + default: + throw new FormatException("Bitmap.Pixelformat."+destinationBitmap.PixelFormat+" is currently not supported. Supported: Format32bpp(A)Rgb, Format24bppRgb"); + } + long ticks = DateTime.Now.Ticks; + unsafe { + int width = destRectangle.Width - (blurRadius*2); + int height = destRectangle.Height - (blurRadius*2); + int diameter = (2 * blurRadius) + 1; + int mid = ((diameter-1)/2) + 1; + int midPixel = mid * bytesPerPixel; + int midLine = (mid - 1) * destStride; + int writeRPixelOffset = midLine + midPixel + rIndex; + int writeGPixelOffset = midLine + midPixel + gIndex; + int writeBPixelOffset = midLine + midPixel + bIndex; + int readRPixelOffset = diameter * bytesPerPixel + rIndex; + int readGPixelOffset = diameter * bytesPerPixel + gIndex; + int readBPixelOffset = diameter * bytesPerPixel + bIndex; + + int destOffset = destStride - (width*bytesPerPixel); + int srcOffset = srcStride - (width*bytesPerPixel); + int factor = diameter * diameter; + + byte *destBitmapPointer = (byte *)(void *)destScan0; + byte *srcBitmapPointer = (byte *)(void *)srcScan0; + int pixel, lineOffset; + + int rTotal, gTotal, bTotal; + int [,]r = new int[diameter,diameter]; + int [,]g = new int[diameter,diameter]; + int [,]b = new int[diameter,diameter]; + for (int y=0; y < height; y++) { + // Reset totals + rTotal = gTotal = bTotal = 0; + + // Intial load: Do the complete radius, fill the arrays with their values + lineOffset = 0; // Offset relative to the srcBitmapPointer + // Vertical loop + for (int v = 0; v < diameter; v++) { + // Start at beginning of the current line + int index = lineOffset; + // Horizontal loop + for (int currentRow = 0; currentRow < diameter; currentRow++) { + // Get & add values + rTotal += r[v,currentRow] = srcBitmapPointer[index + rIndex]; + gTotal += g[v,currentRow] = srcBitmapPointer[index + gIndex]; + bTotal += b[v,currentRow] = srcBitmapPointer[index + bIndex]; + // Move 1px to the right + index += bytesPerPixel; + } + // Move to next line + lineOffset += srcStride; + } + + // Now loop the complete line from left to right + for (int x=0; x < width; x++ ) { + // Draw Pixel with calculated values + pixel = rTotal / factor; + if (pixel < 0) pixel = 0; + if (pixel > 255) pixel = 255; + destBitmapPointer[writeRPixelOffset]= (byte)pixel; + + pixel = gTotal / factor; + if (pixel < 0) pixel = 0; + if (pixel > 255) pixel = 255; + destBitmapPointer[writeGPixelOffset]= (byte)pixel; + + pixel = bTotal / factor; + if (pixel < 0) pixel = 0; + if (pixel > 255) pixel = 255; + destBitmapPointer[writeBPixelOffset]= (byte)pixel; + + // Update values with next "row" + int oldRow = x % diameter; + srcBitmapPointer += bytesPerPixel; + lineOffset = 0; + // Vertical Loop, subtract the stored value and add the new value + for (int v = 0; v < diameter; v++) { + // Subtrace the first value, so we can add the new later + rTotal -= r[v, oldRow]; + gTotal -= g[v, oldRow]; + bTotal -= b[v, oldRow]; + + // Get & add the next values + rTotal += r[v, oldRow] = srcBitmapPointer[readRPixelOffset + lineOffset]; + gTotal += g[v, oldRow] = srcBitmapPointer[readGPixelOffset + lineOffset]; + bTotal += b[v, oldRow] = srcBitmapPointer[readBPixelOffset + lineOffset]; + + // Goto next line + lineOffset += srcStride; + } + destBitmapPointer += bytesPerPixel; + } + srcBitmapPointer += srcOffset; + destBitmapPointer += destOffset; + } + } + LOG.Info("Ticks = " + (DateTime.Now.Ticks - ticks)); + + destinationBitmap.UnlockBits(destbitmapData); + sourceBitmap.UnlockBits(srcBitmapData); + return true; + } + + /** + * Checks if the supplied Bitmap has a PixelFormat we support + */ + private bool SupportsPixelFormat(Bitmap bitmap) { + return (bitmap.PixelFormat.Equals(PixelFormat.Format32bppArgb) || + bitmap.PixelFormat.Equals(PixelFormat.Format32bppRgb) || + bitmap.PixelFormat.Equals(PixelFormat.Format24bppRgb)); + } + + } +} diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/Greenshot/Drawing/Filters/GrayscaleFilter.cs new file mode 100644 index 000000000..3eb568bba --- /dev/null +++ b/Greenshot/Drawing/Filters/GrayscaleFilter.cs @@ -0,0 +1,48 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.Serialization; + +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing.Filters { + /// + /// Description of GrayscaleFilter. + /// + [Serializable()] + public class GrayscaleFilter : AbstractFilter { + public GrayscaleFilter(DrawableContainer parent) : base(parent) { + } + + protected override void IteratePixel(int x, int y) { + Color color = bbb.GetColorAt(x, y); + int luma = (int)((0.3*color.R) + (0.59*color.G) + (0.11*color.B)); + color = Color.FromArgb(luma, luma, luma); + bbb.SetColorAt(x, y, color); + } + + public override void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode) { + base.Apply(graphics, bmp, rect, renderMode); + } + } +} diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/Greenshot/Drawing/Filters/HighlightFilter.cs new file mode 100644 index 000000000..3922a8ab2 --- /dev/null +++ b/Greenshot/Drawing/Filters/HighlightFilter.cs @@ -0,0 +1,51 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.Serialization; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing.Filters { + [Serializable()] + public class HighlightFilter : AbstractFilter { + [NonSerialized] + private Color highlightColor; + + public HighlightFilter(DrawableContainer parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.FILL_COLOR, GetType(), Color.Yellow)); + } + + protected override void IteratePixel(int x, int y) { + Color color = bbb.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)); + bbb.SetColorAt(x, y, color); + } + + public override void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode) { + highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + base.Apply(graphics, bmp, rect, renderMode); + } + } +} diff --git a/Greenshot/Drawing/Filters/IFilter.cs b/Greenshot/Drawing/Filters/IFilter.cs new file mode 100644 index 000000000..a556dd998 --- /dev/null +++ b/Greenshot/Drawing/Filters/IFilter.cs @@ -0,0 +1,37 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; + +using Greenshot.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing.Filters { + public interface IFilter : INotifyPropertyChanged, IFieldHolder { + DrawableContainer Parent {get; set; } + void Apply(Graphics graphics, Bitmap bmp, RenderMode renderMode); + void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode); + DrawableContainer GetParent(); + } +} diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs new file mode 100644 index 000000000..98678c931 --- /dev/null +++ b/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -0,0 +1,65 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.Serialization; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing.Filters { + [Serializable()] + public class MagnifierFilter : AbstractFilter { + + private BitmapBuffer bbbSrc; + private int magnificationFactor; + + public MagnifierFilter(DrawableContainer parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.MAGNIFICATION_FACTOR)); + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { + magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); + applyRect = IntersectRectangle(applyBitmap.Size, rect); + + bbbSrc = new BitmapBuffer(applyBitmap, applyRect); + try { + bbbSrc.Lock(); + base.Apply(graphics, applyBitmap, applyRect, renderMode); + } finally { + bbbSrc.Dispose(); + bbbSrc = null; + } + } + + protected override void IteratePixel(int x, int y) { + int halfWidth = bbb.Size.Width/2; + int halfHeight = bbb.Size.Height/2; + int yDistanceFromCenter = halfHeight-y; + int xDistanceFromCenter = halfWidth-x; + Color color = bbbSrc.GetColorAt(halfWidth-xDistanceFromCenter/magnificationFactor,halfHeight-yDistanceFromCenter/magnificationFactor); + bbb.SetColorAt(x, y, color); + } + } + +} diff --git a/Greenshot/Drawing/Filters/PixelizationFilter.cs b/Greenshot/Drawing/Filters/PixelizationFilter.cs new file mode 100644 index 000000000..31f3a965a --- /dev/null +++ b/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -0,0 +1,82 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.Serialization; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing.Filters { + [Serializable()] + public class PixelizationFilter : AbstractFilter { + + public PixelizationFilter(DrawableContainer parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.PIXEL_SIZE)); + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { + applyRect = IntersectRectangle(applyBitmap.Size, rect); + + int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); + if(pixelSize <= 1 || applyRect.Width == 0 || applyRect.Height == 0) { + // Nothing to do + return; + } + if(applyRect.Width < pixelSize) pixelSize = applyRect.Width; + if(applyRect.Height < pixelSize) pixelSize = applyRect.Height; + + using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, applyRect)) { + bbbDest.Lock(); + using(BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, applyRect)) { + bbbSrc.Lock(); + List colors = new List(); + int halbPixelSize = pixelSize/2; + for(int y=-halbPixelSize;y=0 && yy < bbbSrc.Height) { + for(int xx=x;xx=0 && yy < bbbSrc.Height) { + for(int xx=x;xx<=x+pixelSize;xx++) { + bbbDest.SetColorAt(xx, yy, currentAvgColor); + } + } + } + } + } + } + bbbDest.DrawTo(graphics, applyRect.Location); + } + } + } +} diff --git a/Greenshot/Drawing/HighlightContainer.cs b/Greenshot/Drawing/HighlightContainer.cs new file mode 100644 index 000000000..cc526d1b7 --- /dev/null +++ b/Greenshot/Drawing/HighlightContainer.cs @@ -0,0 +1,83 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Runtime.Serialization; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; + +namespace Greenshot.Drawing { + /// + /// Description of ObfuscateContainer. + /// + [Serializable()] + public class HighlightContainer : FilterContainer { + public HighlightContainer(Surface parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.PREPARED_FILTER_HIGHLIGHT)); + init(); + } + + [OnDeserializedAttribute()] + private void OnDeserialized(StreamingContext context) { + init(); + } + + private void init() { + FieldChanged += HighlightContainer_OnFieldChanged; + ConfigurePreparedFilters(); + } + + protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { + if(sender.Equals(this)) { + if (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: + AbstractFilter bf = new BrightnessFilter(this); + bf.Invert = true; + Add(bf); + bf = new BlurFilter(this); + bf.Invert = true; + Add(bf); + break; + case PreparedFilter.GRAYSCALE: + AbstractFilter f = new GrayscaleFilter(this); + f.Invert = true; + Add(f); + break; + case PreparedFilter.MAGNIFICATION: + Add(new MagnifierFilter(this)); + break; + } + } + } +} diff --git a/Greenshot/Drawing/HtmlContainer.cs b/Greenshot/Drawing/HtmlContainer.cs new file mode 100644 index 000000000..a00ebfdf5 --- /dev/null +++ b/Greenshot/Drawing/HtmlContainer.cs @@ -0,0 +1,124 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.IO; +using System.Runtime.Serialization; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of BitmapContainer. + /// + [Serializable()] + public class HtmlContainer : DrawableContainer { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(HtmlContainer)); + private const string SCRIPT_PATTERN = ""; + private string html = null; + private Bitmap bitmap = null; + private Size lastSize = new Size(0,0); + + public HtmlContainer(Surface parent, string html) : this(parent) { + Html = html; + } + + public HtmlContainer(Surface parent) : base(parent) { + Width = 100; + Height = 100; + } + + private void removeScripts() { + Regex regExRemoveScript = new Regex(SCRIPT_PATTERN); + html = regExRemoveScript.Replace(html, ""); + } + + public string Html { + set { + html = value; + removeScripts(); + lastSize = new Size(0, 0); + RedrawIfNeeded(); + } + get { return html; } + } + + /** + * Destructor + */ + ~HtmlContainer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public new void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + // 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 virtual void Dispose(bool disposing) { + if (disposing) { + if (bitmap != null) { + bitmap.Dispose(); + } + } + bitmap = null; + } + + protected void RedrawIfNeeded() { + if (html == null) { + if (bitmap != null) { + bitmap.Dispose(); + } + bitmap = null; + return; + } + if (bitmap == null || lastSize.Height != Height || lastSize.Width != Width) { + bitmap = WebsiteImageGenerator.GetImageFromHTML(html); + if (bitmap != null) { + lastSize = new Size(bitmap.Width, bitmap.Height); + } + } + } + + public override void Draw(Graphics g, RenderMode rm) { + RedrawIfNeeded(); + if (bitmap != null) { + g.DrawImage(bitmap, Bounds); + } + } + } +} diff --git a/Greenshot/Drawing/IconContainer.cs b/Greenshot/Drawing/IconContainer.cs new file mode 100644 index 000000000..b1063aaf2 --- /dev/null +++ b/Greenshot/Drawing/IconContainer.cs @@ -0,0 +1,108 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.IO; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of IconContainer. + /// + [Serializable()] + public class IconContainer : DrawableContainer, IIconContainer { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IconContainer)); + + protected Icon icon; + + public IconContainer(Surface parent) : base(parent) { + } + + public IconContainer(Surface parent, string filename) : base(parent) { + Load(filename); + } + + public Icon Icon { + set { + if (icon != null) { + icon.Dispose(); + } + icon = (Icon)value.Clone(); + Width = value.Width; + Height = value.Height; + } + get { return icon; } + } + + /** + * Destructor + */ + ~IconContainer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public new void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + // 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 virtual void Dispose(bool disposing) { + if (disposing) { + if (icon != null) { + icon.Dispose(); + } + } + icon = null; + } + + public void Load(string filename) { + if (File.Exists(filename)) { + 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) { + graphics.DrawIcon(icon, Bounds); + } + } + } +} diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs new file mode 100644 index 000000000..637135e1d --- /dev/null +++ b/Greenshot/Drawing/LineContainer.cs @@ -0,0 +1,107 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of LineContainer. + /// + [Serializable()] + public class LineContainer : DrawableContainer { + + public static readonly int MAX_CLICK_DISTANCE_TOLERANCE = 10; + + public LineContainer(Surface parent) : base(parent) { + Init(); + AddField(FieldFactory.CreateField(FieldType.LINE_THICKNESS)); + AddField(FieldFactory.CreateField(FieldType.LINE_COLOR)); + AddField(FieldFactory.CreateField(FieldType.SHADOW)); + } + + private void Init() { + grippers[1].Enabled = false; + grippers[2].Enabled = false; + grippers[3].Enabled = false; + grippers[5].Enabled = false; + grippers[6].Enabled = false; + grippers[7].Enabled = false; + } + + public override void Draw(Graphics g, RenderMode rm) { + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + + if ( shadow && lineThickness > 0 ) { + //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))) { + shadowCapPen.Width = lineThickness; + + g.DrawLine(shadowCapPen, + this.Left + currentStep, + this.Top + currentStep, + this.Left + currentStep + this.Width, + this.Top + currentStep + this.Height); + + currentStep++; + alpha = alpha - (basealpha / steps); + } + } + } + + + using (Pen pen = new Pen(lineColor)) { + pen.Width = lineThickness; + + if(pen.Width > 0) { + g.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); + } + } + } + + public override bool ClickableAt(int x, int y) { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + double distance = DrawingHelper.CalculateLinePointDistance(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height, x, y); + if (distance < 0) { + return false; + } + return distance <= Math.Max(lineThickness / 2, MAX_CLICK_DISTANCE_TOLERANCE); + } + + } +} diff --git a/Greenshot/Drawing/MetafileContainer.cs b/Greenshot/Drawing/MetafileContainer.cs new file mode 100644 index 000000000..840150848 --- /dev/null +++ b/Greenshot/Drawing/MetafileContainer.cs @@ -0,0 +1,123 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of MetafileContainer. + /// + [Serializable()] + public class MetafileContainer : DrawableContainer, IMetafileContainer { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(MetafileContainer)); + + protected Metafile metafile; + + public MetafileContainer(Surface parent) : base(parent) { + } + + public MetafileContainer(Surface parent, string filename) : base(parent) { + Load(filename); + } + + public Metafile Metafile { + set { + if (metafile != null) { + metafile.Dispose(); + } + metafile = (Metafile)value.Clone(); + Height = Math.Abs(value.Height); + if (Height == 0 ) { + Height = 100; + } + Width = Math.Abs(value.Width); + if (Width == 0 ) { + Width = 100; + } + while (Height > parent.Height) { + Height = Height / 4; + Width = Width / 4; + } + while (Width > parent.Width) { + Height = Height / 4; + Width = Width / 4; + } + } + get { return metafile; } + } + + /** + * Destructor + */ + ~MetafileContainer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public new void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + // 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 virtual void Dispose(bool disposing) { + if (disposing) { + if (metafile != null) { + metafile.Dispose(); + } + } + metafile = null; + } + + public void Load(string filename) { + if (File.Exists(filename)) { + using (Metafile fileMetafile = new Metafile(filename)) { + Metafile = fileMetafile; + LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); + } + } + } + + public override void Draw(Graphics graphics, RenderMode rm) { + if (metafile != null) { + graphics.DrawImage(metafile, Bounds); + } + } + } +} diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/Greenshot/Drawing/ObfuscateContainer.cs new file mode 100644 index 000000000..70297af48 --- /dev/null +++ b/Greenshot/Drawing/ObfuscateContainer.cs @@ -0,0 +1,70 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Runtime.Serialization; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; + +namespace Greenshot.Drawing { + /// + /// Description of ObfuscateContainer. + /// + [Serializable()] + public class ObfuscateContainer : FilterContainer { + public ObfuscateContainer(Surface parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.PREPARED_FILTER_OBFUSCATE)); + init(); + } + + [OnDeserializedAttribute()] + private void OnDeserialized(StreamingContext context) { + init(); + } + + private void init() { + FieldChanged += ObfuscateContainer_OnFieldChanged; + ConfigurePreparedFilters(); + } + + protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { + if(sender.Equals(this)) { + if(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 new file mode 100644 index 000000000..e80741d99 --- /dev/null +++ b/Greenshot/Drawing/RectangleContainer.cs @@ -0,0 +1,90 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Represents a rectangular shape on the Surface + /// + [Serializable()] + public class RectangleContainer : DrawableContainer { + + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(RectangleContainer)); + + public RectangleContainer(Surface parent) : base(parent) { + AddField(FieldFactory.CreateField(FieldType.LINE_THICKNESS)); + AddField(FieldFactory.CreateField(FieldType.LINE_COLOR)); + AddField(FieldFactory.CreateField(FieldType.FILL_COLOR)); + AddField(FieldFactory.CreateField(FieldType.SHADOW)); + } + + + public override void Draw(Graphics g, RenderMode rm) { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + 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))) { + shadowPen.Width = lineVisible ? lineThickness : 1; + Rectangle shadowRect = GuiRectangle.GetGuiRectangle( + this.Left + currentStep, + this.Top + currentStep, + this.Width, + this.Height); + g.DrawRectangle(shadowPen, shadowRect); + currentStep++; + alpha = alpha - (basealpha / steps); + } + } + } + + Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); + + using (Brush brush = new SolidBrush(fillColor)) { + g.FillRectangle(brush, rect); + } + + using (Pen pen = new Pen(lineColor)) { + pen.Width = lineThickness; + if(pen.Width > 0) { + g.DrawRectangle(pen, rect); + } + } + } + + } +} diff --git a/Greenshot/Drawing/RoundedRectangle.cs b/Greenshot/Drawing/RoundedRectangle.cs new file mode 100644 index 000000000..228b989bb --- /dev/null +++ b/Greenshot/Drawing/RoundedRectangle.cs @@ -0,0 +1,130 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace Greenshot.Drawing { + public abstract class RoundedRectangle { + public enum RectangleCorners { + None = 0, TopLeft = 1, TopRight = 2, + BottomLeft = 4, BottomRight = 8, + All = TopLeft | TopRight | BottomLeft | BottomRight + } + + public static GraphicsPath Create2(int x, int y, int width, int height, int radius) { + GraphicsPath 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; + } + + public static GraphicsPath Create(int x, int y, int width, int height, int radius, RectangleCorners corners) { + int xw = x + width; + int yh = y + height; + int xwr = xw - radius; + int yhr = yh - radius; + int xr = x + radius; + int yr = y + radius; + int r2 = radius * 2; + int xwr2 = xw - r2; + int yhr2 = yh - r2; + + GraphicsPath p = new GraphicsPath(); + p.StartFigure(); + + //Top Left Corner + if ((RectangleCorners.TopLeft & corners) == RectangleCorners.TopLeft) { + p.AddArc(x, y, r2, r2, 180, 90); + } else { + p.AddLine(x, yr, x, y); + p.AddLine(x, y, xr, y); + } + + //Top Edge + p.AddLine(xr, y, xwr, y); + + //Top Right Corner + if ((RectangleCorners.TopRight & corners) == RectangleCorners.TopRight) { + p.AddArc(xwr2, y, r2, r2, 270, 90); + } else { + p.AddLine(xwr, y, xw, y); + p.AddLine(xw, y, xw, yr); + } + + //Right Edge + p.AddLine(xw, yr, xw, yhr); + + //Bottom Right Corner + if ((RectangleCorners.BottomRight & corners) == RectangleCorners.BottomRight) { + p.AddArc(xwr2, yhr2, r2, r2, 0, 90); + } else { + p.AddLine(xw, yhr, xw, yh); + p.AddLine(xw, yh, xwr, yh); + } + + //Bottom Edge + p.AddLine(xwr, yh, xr, yh); + + //Bottom Left Corner + if ((RectangleCorners.BottomLeft & corners) == RectangleCorners.BottomLeft) { + p.AddArc(x, yhr2, r2, r2, 90, 90); + } else { + p.AddLine(xr, yh, x, yh); + p.AddLine(x, yh, x, yhr); + } + + //Left Edge + p.AddLine(x, yhr, x, yr); + + p.CloseFigure(); + return p; + } + + public static GraphicsPath Create(Rectangle rect, int radius, RectangleCorners corners) { + return Create(rect.X, rect.Y, rect.Width, rect.Height, radius, corners); + } + + public static GraphicsPath Create(int x, int y, int width, int height, int radius) { + return Create(x, y, width, height, radius, RectangleCorners.All); + } + + public static GraphicsPath Create(Rectangle rect, int radius) { + return Create(rect.X, rect.Y, rect.Width, rect.Height, radius); + } + + public static GraphicsPath Create(int x, int y, int width, int height) { + return Create(x, y, width, height, 5); + } + + public static GraphicsPath Create(Rectangle rect) { + return Create(rect.X, rect.Y, rect.Width, rect.Height); + } + } +} diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs new file mode 100644 index 000000000..ddf2dd306 --- /dev/null +++ b/Greenshot/Drawing/Surface.cs @@ -0,0 +1,852 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; +using Greenshot.Helpers; +using Greenshot.Plugin; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + public delegate void SurfaceElementEventHandler(object source, DrawableContainerList element); + public delegate void SurfaceDrawingModeEventHandler(object source, DrawingModes drawingMode); + + public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap } + /// + /// Description of Surface. + /// + public class Surface : PictureBox, ISurface { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(Surface)); + public event SurfaceElementEventHandler MovingElementChanged; + public event SurfaceDrawingModeEventHandler DrawingModeChanged; + + public FieldAggregator FieldAggregator = new FieldAggregator(); + + private AppConfig conf = AppConfig.GetInstance(); + private ICaptureDetails captureDetails = null; + + private int mX; + private int mY; + private bool mouseDown = false; + private bool draggingInProgress = false; + private DrawableContainer mouseDownElement = null; + + private Image originalImage; + + private DrawableContainerList elements = new DrawableContainerList(); + + private DrawableContainerList selectedElements = new DrawableContainerList(); + private DrawableContainer drawingElement = null; + private DrawableContainer undrawnElement = null; + private DrawableContainer cropContainer = null; + + public bool KeysLocked = false; + + private DrawingModes drawingMode = DrawingModes.None; + public DrawingModes DrawingMode { + get {return drawingMode;} + set { + drawingMode = value; + DrawingModeChanged.Invoke(this, drawingMode); + DeselectAllElements(); + CreateUndrawnElement(); + } + } + + public Image OriginalImage { + get { return originalImage; } + } + + public ICaptureDetails CaptureDetails { + get {return captureDetails;} + set {captureDetails = value;} + } + + public Surface() { + LOG.Debug("Creating a surface!"); + SizeMode = PictureBoxSizeMode.AutoSize; + this.MouseDown += new MouseEventHandler(SurfaceMouseDown); + this.MouseUp += new MouseEventHandler(SurfaceMouseUp); + this.MouseMove += new MouseEventHandler(SurfaceMouseMove); + this.MouseDoubleClick += new MouseEventHandler(SurfaceDoubleClick); + this.Paint += new PaintEventHandler(SurfacePaint); + this.AllowDrop = true; + this.DragDrop += new DragEventHandler(OnDragDrop); + this.DragEnter += new DragEventHandler(OnDragEnter); + } + + private void SetImage(Image image) { + if (originalImage != null) { + originalImage.Dispose(); + } + if (Image != null) { + Image.Dispose(); + } + originalImage = new Bitmap(image); + Image = new Bitmap(image); + } + + public Surface(Image image) : this() { + LOG.Debug("Got image with dimensions " + image.Width + "," + image.Height + " bpp: " + image.PixelFormat); + SetImage(image); + } + + public Surface(ICapture capture) : this(capture.Image) { + if (capture.Cursor != null && capture.CursorVisible) { + SelectElement(AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y)); + } + captureDetails = capture.CaptureDetails; + } + + public void SaveElementsToStream(Stream streamWrite) { + try { + BinaryFormatter binaryWrite = new BinaryFormatter(); + binaryWrite.Serialize(streamWrite, elements); + } catch (Exception e) { + LOG.Error("Error serializing elements to stream.", e); + } + } + + public void LoadElementsFromStream(Stream streamRead) { + try { + BinaryFormatter binaryRead = new BinaryFormatter(); + DrawableContainerList loadedElements = (DrawableContainerList) binaryRead.Deserialize(streamRead); + if (loadedElements != null) { + loadedElements.Parent = this; + DeselectAllElements(); + AddElements(loadedElements); + SelectElements(loadedElements); + FieldAggregator.BindElements(loadedElements); + } + } catch (Exception e) { + LOG.Error("Error serializing elements from stream.", e); + } + } + + 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.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 BitmapContainer(this); + break; + case DrawingModes.None: + undrawnElement = null; + break; + } + if (undrawnElement != null) { + FieldAggregator.BindElement(undrawnElement); + } + } + + #region Plugin interface implementations + public IBitmapContainer AddBitmapContainer(Bitmap bitmap, int x, int y) { + BitmapContainer bitmapContainer = new BitmapContainer(this); + bitmapContainer.Bitmap = bitmap; + bitmapContainer.Left = x; + bitmapContainer.Top = y; + AddElement(bitmapContainer); + return bitmapContainer; + } + private HtmlContainer AddHtmlContainer(string html, int x, int y) { + HtmlContainer htmlContainer = new HtmlContainer(this); + htmlContainer.Left = x; + htmlContainer.Top = y; + htmlContainer.Html = html; + AddElement(htmlContainer); + return htmlContainer; + } + private UrlContainer AddUrlContainer(string url, int x, int y) { + UrlContainer urlContainer = new UrlContainer(this); + urlContainer.Left = x; + urlContainer.Top = y; + urlContainer.Url = url; + AddElement(urlContainer); + return urlContainer; + } + public IBitmapContainer AddBitmapContainer(string filename, int x, int y) { + BitmapContainer bitmapContainer = new BitmapContainer(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); + iconContainer.Icon = icon; + iconContainer.Left = x; + iconContainer.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); + cursorContainer.Cursor = cursor; + cursorContainer.Left = x; + cursorContainer.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 IMetafileContainer AddMetafileContainer(string filename, int x, int y) { + MetafileContainer metafileContainer = new MetafileContainer(this); + metafileContainer.Load(filename); + metafileContainer.Left = x; + metafileContainer.Top = y; + AddElement(metafileContainer); + return metafileContainer; + } + public IMetafileContainer AddMetafileContainer(Metafile metafile, int x, int y) { + MetafileContainer metafileContainer = new MetafileContainer(this); + metafileContainer.Metafile = metafile; + metafileContainer.Left = x; + metafileContainer.Top = y; + AddElement(metafileContainer); + return metafileContainer; + } + + public ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) { + TextContainer textContainer = new TextContainer(this); + textContainer.Text = text; + 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(); + // Align to Surface + textContainer.AlignToParent(horizontalAlignment, verticalAlignment); + + //AggregatedProperties.UpdateElement(textContainer); + AddElement(textContainer); + return textContainer; + } + #endregion + + #region DragDrop + private List GetFilenames(DragEventArgs e) { + List filenames = new List(); + string[] dropFileNames = (string[])e.Data.GetData(DataFormats.FileDrop); + if (dropFileNames != null && dropFileNames.Length > 0) { + foreach(string filename in dropFileNames) { + LOG.Debug("Found filename: " + filename); + string ext=Path.GetExtension(filename).ToLower(); + if ((ext==".jpg") || (ext==".gif") || (ext==".png") || (ext==".bmp")) { + filenames.Add(filename); + } + } + } + return filenames; + } + + private void OnDragEnter(object sender, DragEventArgs e) { + if(LOG.IsDebugEnabled) { + LOG.Debug("DragEnter got following formats: "); + foreach(string format in e.Data.GetFormats()) { + LOG.Debug(format); + } + } + if (draggingInProgress || (e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) { + e.Effect=DragDropEffects.None; + } else { + List filenames = GetFilenames(e); + if ( (filenames != null && filenames.Count > 0) + || e.Data.GetDataPresent(DataFormats.Bitmap, true) + //|| e.Data.GetDataPresent(DataFormats.EnhancedMetafile, true) + ) { + e.Effect=DragDropEffects.Copy; + } else { + e.Effect=DragDropEffects.None; + } + } + } + + private void OnDragDrop(object sender, DragEventArgs e) { + List filenames = GetFilenames(e); + Point mouse = this.PointToClient(new Point(e.X, e.Y)); + if ((filenames != null && filenames.Count > 0)) { + foreach(string filename in filenames) { + LOG.Debug("Drop - filename: " + filename); + AddBitmapContainer(filename, mouse.X, mouse.Y); + mouse.Offset(10, 10); + } + } else if (e.Data.GetDataPresent(DataFormats.Bitmap)) { + AddBitmapContainer((Bitmap)e.Data.GetData(DataFormats.Bitmap, true), mouse.X, mouse.Y); +// } else if (e.Data.GetDataPresent(DataFormats.EnhancedMetafile)) { +// AddBitmapContainer((Image)e.Data.GetData(DataFormats.EnhancedMetafile, true), mouse.X, mouse.Y); + } + } + +// private void QueryContinueDragDrop(object sender, QueryContinueDragEventArgs e) { +// LOG.Debug("QueryContinueDrag: " + e.Action); +// if (e.EscapePressed) { +// e.Action = DragAction.Cancel; +// } +// } +// +// private void GiveFeedbackDragDrop(object sender, GiveFeedbackEventArgs e) { +// e.UseDefaultCursors = true; +// } + #endregion + + void ApplyCrop() { + Rectangle r = cropContainer.Bounds; + r = Helpers.GuiRectangle.GetGuiRectangle(r.Left, r.Top, r.Width, r.Height); + if (r.Left < 0) r = new Rectangle(0, r.Top, r.Width + r.Left, r.Height); + if (r.Top < 0) r = new Rectangle(r.Left, 0, r.Width, r.Height + r.Top); + if (r.Left + r.Width > Width) r = new Rectangle(r.Left, r.Top, Width - r.Left, r.Height); + if (r.Top + r.Height > Height) r = new Rectangle(r.Left, r.Top, r.Width, Height - r.Top); + + if (r.Height > 0 && r.Width > 0) { + // we should not forget to Dispose the images!! + using (Bitmap tmpImage = ((Bitmap)originalImage).Clone(r, originalImage.PixelFormat)) { + tmpImage.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution); + SetImage(tmpImage); + elements.MoveBy(-r.Left, -r.Top); + } + } + } + + void SurfaceMouseDown(object sender, MouseEventArgs e) { + mX = e.X; mY = e.Y; + mouseDown = true; + + if (cropContainer != null && ((undrawnElement == null) || (undrawnElement != null && DrawingMode != DrawingModes.Crop))) { + RemoveElement(cropContainer); + cropContainer = null; + drawingElement = null; + } + + if(drawingElement == null && DrawingMode != DrawingModes.None) { + if (undrawnElement == null) { + DeselectAllElements(); + if(undrawnElement == null) { + CreateUndrawnElement(); + } + } + drawingElement = undrawnElement; + drawingElement.Status = EditStatus.DRAWING; + undrawnElement = null; + // if a new element has been drawn, set location and register it + if (drawingElement != null) { + drawingElement.PropertyChanged += ElementPropertyChanged; + drawingElement.Left = e.X; + drawingElement.Top = e.Y; + AddElement(drawingElement); + drawingElement.Selected = true; + } + } 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(e.X, e.Y); + if(mouseDownElement != null) { + mouseDownElement.Status = EditStatus.MOVING; + } + } + } + + void SurfaceMouseUp(object sender, MouseEventArgs e) { + 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 + DrawableContainer element = elements.ClickableElementAt(e.X, e.Y); + bool shiftModifier = (Control.ModifierKeys & Keys.Shift) == Keys.Shift; + if(element != null) { + 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.ShowGrippers(); + selectedElements.Selected = true; + } + + if (drawingElement != null) { + if (!drawingElement.InitContent()) { + elements.Remove(drawingElement); + Invalidate(); + } else { + if (Math.Abs(drawingElement.Width) < 5 && Math.Abs(drawingElement.Height) < 5) { + drawingElement.Width = 25; + drawingElement.Height = 25; + } + SelectElement(drawingElement); + drawingElement.Selected = true; + } + drawingElement = null; + } + Invalidate(); + } + + void SurfaceMouseMove(object sender, MouseEventArgs e) { + if (DrawingMode != DrawingModes.None) { + Cursor = Cursors.Cross; + } else { + Cursor = Cursors.Default; + } + + if(mouseDown) { + if(mouseDownElement != null) { // an element is currently dragged + selectedElements.HideGrippers(); + if(mouseDownElement.Selected) { // dragged element has been selected before -> move all + selectedElements.MoveBy(e.X - mX, e.Y - mY); + } else { // dragged element is not among selected elements -> just move dragged one + mouseDownElement.MoveBy(e.X - mX, e.Y - mY); + } + mX = e.X; mY = e.Y; + Invalidate(); + } else if(drawingElement != null) { // an element is currently drawn + drawingElement.Width = e.X - drawingElement.Left; + drawingElement.Height = e.Y - drawingElement.Top; + Invalidate(); +// } else { +// // Enable DragDrop +// using (Bitmap bitmapToDrag = GetImageForExport()) { +// +// IDataObject dataObj = new DataObject(); +// string filename = Path.GetTempFileName() + ".png"; +// try { +// bitmapToDrag.Save(filename, ImageFormat.Png); +// LOG.Debug("FileDrop : " + filename); +// dataObj.SetData("HTML Format", true, ""); +// //dataObj.SetData(DataFormats.FileDrop, new string[] {filename}); +// LOG.Debug("Starting DoDragDrop"); +// draggingInProgress = true; +// DoDragDrop(dataObj, DragDropEffects.Copy); +// LOG.Debug("Finished DoDragDrop"); +// draggingInProgress = false; +// mouseDown = false; +// } catch (Exception ex) { +// LOG.Error("Error in DragDrop: ", ex); +// } finally { +// File.Delete(filename); +// } +// } + } + } + } + + void SurfaceDoubleClick(object sender, MouseEventArgs e) { + selectedElements.OnDoubleClick(); + Invalidate(); + } + + private Image GetImage(RenderMode renderMode) { + Image clone = new Bitmap(Image); + // This actually generates a copy of the original image with a dpi equal to the default... + // otherwise we would have a problem drawing the image to the surface... :( + using (Graphics graphics = Graphics.FromImage(clone)) { + graphics.DrawImage(originalImage, Point.Empty); + elements.Draw(graphics, (Bitmap)clone, renderMode); + } + return clone; + } + + public Image GetImageForExport() { + return GetImage(RenderMode.EXPORT); + } + + void SurfacePaint(object sender, PaintEventArgs e) { + Graphics graphics = e.Graphics; + using (Image image = GetImage(RenderMode.EDIT)) { + graphics.DrawImage(image, Point.Empty); + } + // Should be something like this, but due to the filter structure this won't work + //graphics.DrawImage(originalImage, Point.Empty); + //elements.Draw(graphics, (Bitmap)Image, RenderMode.EDIT); + } + + public void AddElement(DrawableContainer element) { + elements.Add(element); + element.FieldChanged += element_FieldChanged; + element.PropertyChanged += ElementPropertyChanged; + if(element.Status == EditStatus.UNDRAWN) element.Status = EditStatus.IDLE; + Invalidate(); + } + + public void RemoveElement(DrawableContainer element) { + DeselectElement(element); + elements.Remove(element); + element.FieldChanged -= element_FieldChanged; + element.PropertyChanged -= ElementPropertyChanged; + element.Dispose(); + Invalidate(); + } + + public void AddElements(DrawableContainerList elementsToAdd) { + elements.AddRange(elementsToAdd); + foreach(DrawableContainer element in elementsToAdd) { + element.FieldChanged += element_FieldChanged; + element.PropertyChanged += ElementPropertyChanged; + if(element.Status == EditStatus.UNDRAWN) element.Status = EditStatus.IDLE; + } + Invalidate(); + } + + public bool HasSelectedElements() { + return (selectedElements != null && selectedElements.Count > 0); + } + + public void RemoveSelectedElements() { + if (HasSelectedElements()) { + foreach (DrawableContainer element in selectedElements) { + elements.Remove(element); + element.FieldChanged -= element_FieldChanged; + element.PropertyChanged -= ElementPropertyChanged; + element.Dispose(); + } + selectedElements.Clear(); + MovingElementChanged(this, selectedElements); + Invalidate(); + } + } + + public void CutSelectedElements() { + if (HasSelectedElements()) { + ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), selectedElements); + RemoveSelectedElements(); + } + } + + public void CopySelectedElements() { + if (HasSelectedElements()) { + ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), selectedElements); + } + } + + 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(DrawableContainer dc in selectedDCs){ + if(dc.Equals(cropContainer)){ + if(confirm) { + ApplyCrop(); + } + DrawingMode = DrawingModes.None; + RemoveElement(cropContainer); + cropContainer.Dispose(); + } + } + } + + public void PasteElementFromClipboard() { + List formats = ClipboardHelper.GetFormats(); + 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(DrawableContainerList).FullName)) { + DrawableContainerList dcs = (DrawableContainerList)ClipboardHelper.GetClipboardData(typeof(DrawableContainerList)); + if (dcs != null) { + dcs.Parent = this; + dcs.MoveBy(10,10); + AddElements(dcs); + FieldAggregator.BindElements(dcs); + DeselectAllElements(); + SelectElements(dcs); + } + } else if (Clipboard.ContainsImage()) { + using (Image image = Clipboard.GetImage()) { + if (image != null) { + DeselectAllElements(); + IBitmapContainer bitmapContainer = AddBitmapContainer(image as Bitmap, 0, 0); + SelectElement(bitmapContainer); + } + } + } else if ( ClipboardHelper.GetFormats().Contains("HTML Format")) { + HtmlFragment htmlFragment = HtmlFragment.FromClipboard(); + DeselectAllElements(); + HtmlContainer htmlContainer = AddHtmlContainer(htmlFragment.Fragment, 0, 0); + SelectElement(htmlContainer); + } else if (Clipboard.ContainsText()) { + string text = Clipboard.GetText(); + if (text != null) { + if (text.StartsWith("http://")) { + DeselectAllElements(); + UrlContainer urlContainer = AddUrlContainer(text, 0, 0); + SelectElement(urlContainer); + } else { + DeselectAllElements(); + ITextContainer textContainer = AddTextContainer(text, HorizontalAlignment.Center, VerticalAlignment.CENTER, + FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); + SelectElement(textContainer); + } + } + } + } + + public void DuplicateSelectedElements() { + if(LOG.IsDebugEnabled) LOG.Debug("Duplicating "+selectedElements.Count+" selected elements"); + DrawableContainerList dcs = (DrawableContainerList)Objects.DeepClone(selectedElements); + dcs.Parent = this; + dcs.MoveBy(10,10); + AddElements(dcs); + DeselectAllElements(); + SelectElements(dcs); + } + + public void DeselectElement(IDrawableContainer container) { + DrawableContainer element = container as DrawableContainer; + element.HideGrippers(); + element.Selected = false; + selectedElements.Remove(element); + FieldAggregator.UnbindElement(element); + if (MovingElementChanged != null) { + MovingElementChanged(this, selectedElements); + } + } + + public void DeselectAllElements() { + if (HasSelectedElements()) { + while(selectedElements.Count > 0) { + DrawableContainer element = selectedElements[0]; + element.HideGrippers(); + element.Selected = false; + selectedElements.Remove(element); + FieldAggregator.UnbindElement(element); + } + if (MovingElementChanged != null) { + MovingElementChanged(this, selectedElements); + } + } + } + + public void SelectElement(IDrawableContainer container) { + DrawableContainer element = container as DrawableContainer; + if(!selectedElements.Contains(element)) { + selectedElements.Add(element); + element.ShowGrippers(); + element.Selected = true; + FieldAggregator.BindElement(element); + if (MovingElementChanged != null) { + MovingElementChanged(this, selectedElements); + } + Invalidate(); + } + } + + public void SelectAllElements() { + SelectElements(elements); + } + + public void SelectElements(DrawableContainerList elements) { + foreach(DrawableContainer element in elements) { + SelectElement(element); + } + } + + public void ProcessCmdKey(Keys k) { + if (selectedElements.Count > 0) { + int px = (k == Keys.Shift) ? 10 : 1; + switch (k) { + case Keys.Left: + selectedElements.MoveBy(-1,0); + break; + case Keys.Left | Keys.Shift: + selectedElements.MoveBy(-10,0); + break; + case Keys.Up: + selectedElements.MoveBy(0,-1); + break; + case Keys.Up | Keys.Shift: + selectedElements.MoveBy(0,-10); + break; + case Keys.Right: + selectedElements.MoveBy(1,0); + break; + case Keys.Right | Keys.Shift: + selectedElements.MoveBy(10,0); + break; + case Keys.Down: + selectedElements.MoveBy(0,1); + break; + case Keys.Down | Keys.Shift: + selectedElements.MoveBy(0,10); + break; + case Keys.PageUp: + elements.PullElementsUp(selectedElements); + break; + case Keys.PageDown: + elements.PushElementsDown(selectedElements); + break; + case Keys.Home: + elements.PullElementsToTop(selectedElements); + break; + case Keys.End: + elements.PushElementsToBottom(selectedElements); + break; + case Keys.Enter: + ConfirmSelectedConfirmableElements(true); + break; + case Keys.Escape: + ConfirmSelectedConfirmableElements(false); + break; + /*case Keys.Delete: + RemoveSelectedElements(); + break;*/ + default: + return; + } + Invalidate(); + } + } + + /// + /// pulls selected elements up one level in hierarchy + /// + public void PullElementsUp() { + elements.PullElementsUp(selectedElements); + Invalidate(); + } + + /// + /// pushes selected elements up to top in hierarchy + /// + public void PullElementsToTop() { + elements.PullElementsToTop(selectedElements); + Invalidate(); + } + + /// + /// pushes selected elements down one level in hierarchy + /// + public void PushElementsDown() { + elements.PushElementsDown(selectedElements); + Invalidate(); + } + + /// + /// pushes selected elements down to bottom in hierarchy + /// + public void PushElementsToBottom() { + elements.PushElementsToBottom(selectedElements); + 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 new void Dispose() { + LOG.Debug("Disposing a surface!"); + originalImage.Dispose(); + base.Dispose(); + } + + public void ElementPropertyChanged(object sender, PropertyChangedEventArgs e) { + Invalidate(); + } + + public void element_FieldChanged(object sender, FieldChangedEventArgs e) { + Invalidate(); + } + } +} diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs new file mode 100644 index 000000000..2a0159d40 --- /dev/null +++ b/Greenshot/Drawing/TextContainer.cs @@ -0,0 +1,300 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Text; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Represents a textbox (extends RectangleContainer for border/background support + /// + [Serializable()] + public class TextContainer : RectangleContainer, ITextContainer { + + private bool fontInvalidated = true; + private Font font; + + private string text; + public string Text { + get { return text; } + set { + if((text == null && value != null) || !text.Equals(value)) { + text = value; + OnPropertyChanged("Text"); + } + } + } + + [NonSerialized] + private TextBox textBox; + + public TextContainer(Surface parent) : base(parent) { + Init(); + Field field = FieldFactory.CreateField(FieldType.FONT_BOLD); + //field.PropertyChanged += FontPropertyChanged; + AddField(field); + AddField(FieldFactory.CreateField(FieldType.FONT_ITALIC)); + AddField(FieldFactory.CreateField(FieldType.FONT_FAMILY)); + AddField(FieldFactory.CreateField(FieldType.FONT_SIZE)); + AddField(FieldFactory.CreateField(FieldType.LINE_COLOR, GetType())); + AddField(FieldFactory.CreateField(FieldType.LINE_THICKNESS, GetType())); + AddField(FieldFactory.CreateField(FieldType.FILL_COLOR, GetType())); + AddField(FieldFactory.CreateField(FieldType.SHADOW)); + } + + [OnDeserializedAttribute()] + private void OnDeserialized(StreamingContext context) { + Init(); + UpdateFont(); + } + + /** + * Destructor + */ + ~TextContainer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public override void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + /** + * This Dispose is called from the Dispose and the Destructor. + * When disposing==true all non-managed resources should be freed too! + */ + protected virtual void Dispose(bool disposing) { + if (disposing) { + if(textBox != null) textBox.Dispose(); + if(font != null) font.Dispose(); + } + textBox = null; + font = null; + } + + private void Init() { + CreateTextBox(); + this.PropertyChanged += new PropertyChangedEventHandler(TextContainer_PropertyChanged); + this.FieldChanged += new FieldChangedEventHandler(TextContainer_FieldChanged); + } + + public void FitToText() { + UpdateFont(); + Size textSize = TextRenderer.MeasureText(text, font); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Width = textSize.Width + lineThickness; + Height = textSize.Height + lineThickness; + } + + void TextContainer_PropertyChanged(object sender, PropertyChangedEventArgs e) { + if(e.PropertyName.Equals("Selected")) { + if(!Selected && textBox.Visible) HideTextBox(); + else if(Selected && Status==EditStatus.DRAWING) { + ShowTextBox(); + } + //else if(!textBox.Visible) ShowTextBox(); + } + if(textBox.Visible) { + UpdateTextBoxPosition(); + UpdateTextBoxFormat(); + textBox.Invalidate(); + } + } + + void TextContainer_FieldChanged(object sender, FieldChangedEventArgs e) + { + if(textBox.Visible) { + UpdateTextBoxFormat(); + textBox.Invalidate(); + } else { + UpdateFont(); + //Invalidate(); + } + font.Dispose(); + font = null; + fontInvalidated = true; + } + + public override void OnDoubleClick() { + ShowTextBox(); + } + + private void CreateTextBox() { + textBox = new TextBox(); + textBox.Multiline = true; + textBox.AcceptsTab = false; + textBox.AcceptsReturn = false; + textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged); + textBox.LostFocus += new EventHandler(textBox_LostFocus); + textBox.KeyDown += new KeyEventHandler(textBox_KeyDown); + textBox.BorderStyle = BorderStyle.FixedSingle; + textBox.Visible = false; + } + + private void ShowTextBox() { + childLabel.Hide(); + parent.KeysLocked = true; + parent.Controls.Add(textBox); + textBox.Show(); + textBox.Focus(); + } + + private void HideTextBox() { + childLabel.Show(); + parent.Focus(); + textBox.Hide(); + parent.KeysLocked = false; + parent.Controls.Remove(textBox); + } + + private void UpdateFont() { + string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY); + bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD); + bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC); + float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE); + + if(fontInvalidated && fontFamily != null && fontSize != 0) { + FontStyle fs = FontStyle.Regular; + + bool hasStyle = false; + using(FontFamily fam = new FontFamily(fontFamily)) { + bool boldAvailable = fam.IsStyleAvailable(FontStyle.Bold); + if(fontBold && boldAvailable) { + fs |= FontStyle.Bold; + hasStyle = true; + } + + bool italicAvailable = fam.IsStyleAvailable(FontStyle.Italic); + if(fontItalic && italicAvailable) { + fs |= FontStyle.Italic; + hasStyle = true; + } + + if(!hasStyle) { + bool regularAvailable = fam.IsStyleAvailable(FontStyle.Regular); + if(regularAvailable) { + fs = FontStyle.Regular; + } else { + if(boldAvailable) { + fs = FontStyle.Bold; + } else if(italicAvailable) { + fs = FontStyle.Italic; + } + } + } + + font = new Font(fam, fontSize, fs, GraphicsUnit.Pixel); + } + fontInvalidated = false; + + } + } + + private void UpdateTextBoxPosition() { + textBox.Left = this.Left; + textBox.Top = this.Top; + textBox.Width = this.Width; + textBox.Height = this.Height; + + } + + private void UpdateTextBoxFormat() { + UpdateFont(); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + textBox.ForeColor = lineColor; + textBox.Font = font; + } + + void textBox_KeyDown(object sender, KeyEventArgs e) { + // ESC and Enter/Return (w/o Shift) hide text editor + if(e.KeyCode == Keys.Escape || ((e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) && e.Modifiers != Keys.Shift)) { + HideTextBox(); + e.SuppressKeyPress = true; + } + } + + void textBox_LostFocus(object sender, EventArgs e) { + HideTextBox(); + } + + public override void Draw(Graphics g, RenderMode rm) { + base.Draw(g, rm); + UpdateFont(); + + Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); + if (Selected && !rm.Equals(RenderMode.EXPORT)) { + DrawSelectionBorder(g, rect); + } + + if (text == null || text.Length == 0 ) { + return; + } + + // we only draw the shadow if there is no background + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + int textOffset = (lineThickness>0) ? (int)Math.Ceiling(lineThickness/2d) : 0; + // draw shadow before anything else + if ( shadow && (fillColor == Color.Transparent || fillColor == Color.Empty)) { + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while (currentStep <= steps) { + int offset = currentStep; + Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + offset, Top + offset, Width, Height); + if(lineThickness>0) shadowRect.Inflate(-textOffset, -textOffset); + using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) { + g.DrawString(text, font, fontBrush, shadowRect); + currentStep++; + alpha = alpha - basealpha / steps; + } + } + } + + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + Rectangle fontRect = rect; + if(lineThickness>0) fontRect.Inflate(-textOffset,-textOffset); + using (Brush fontBrush = new SolidBrush(lineColor)) { + g.DrawString(text, font, fontBrush, fontRect); + } + + } + + + } +} diff --git a/Greenshot/Drawing/UrlContainer.cs b/Greenshot/Drawing/UrlContainer.cs new file mode 100644 index 000000000..dd171f84e --- /dev/null +++ b/Greenshot/Drawing/UrlContainer.cs @@ -0,0 +1,117 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.IO; +using System.Runtime.Serialization; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of BitmapContainer. + /// + [Serializable()] + public class UrlContainer : DrawableContainer { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(UrlContainer)); + + protected Bitmap bitmap = null; + protected string url = null; + private Size lastSize = new Size(0, 0); + + public UrlContainer(Surface parent, string url) : this(parent) { + Url = url; + } + + public UrlContainer(Surface parent) : base(parent) { + Width = 100; + Height = 100; + } + + public string Url { + set { + url = value; + lastSize = new Size(0, 0); + RedrawIfNeeded(); + } + get { return url; } + } + + /** + * Destructor + */ + ~UrlContainer() { + Dispose(false); + } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public new void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + // 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 virtual void Dispose(bool disposing) { + if (disposing) { + if (bitmap != null) { + bitmap.Dispose(); + } + } + bitmap = null; + } + + protected void RedrawIfNeeded() { + if (url == null) { + if (bitmap != null) { + bitmap.Dispose(); + } + bitmap = null; + return; + } + if (bitmap == null || lastSize.Height != Height || lastSize.Width != Width) { + bitmap = WebsiteImageGenerator.GetImageFromURL(url); + if (bitmap != null) { + lastSize = new Size(bitmap.Width, bitmap.Height); + } + } + } + + public override void Draw(Graphics g, RenderMode rm) { + RedrawIfNeeded(); + if (bitmap != null) { + g.DrawImage(bitmap, Bounds); + } + } + } +} diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/Greenshot/Forms/AboutForm.Designer.cs new file mode 100644 index 000000000..6bb42c061 --- /dev/null +++ b/Greenshot/Forms/AboutForm.Designer.cs @@ -0,0 +1,255 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Windows.Forms; +using Greenshot.Configuration; + +namespace Greenshot { + partial class AboutForm { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutForm)); + this.lblTitle = new System.Windows.Forms.Label(); + this.lblLicense = new System.Windows.Forms.Label(); + this.lblHost = new System.Windows.Forms.Label(); + this.linkLblLicense = new System.Windows.Forms.LinkLabel(); + this.linkLblHost = new System.Windows.Forms.LinkLabel(); + this.linkLblBugs = new System.Windows.Forms.LinkLabel(); + this.lblBugs = new System.Windows.Forms.Label(); + this.linkLblDonations = new System.Windows.Forms.LinkLabel(); + this.lblDonations = new System.Windows.Forms.Label(); + this.linkLblIcons = new System.Windows.Forms.LinkLabel(); + this.lblIcons = new System.Windows.Forms.Label(); + this.linkLabel1 = new System.Windows.Forms.LinkLabel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.lblTranslation = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // lblTitle + // + this.lblTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTitle.Location = new System.Drawing.Point(108, 12); + this.lblTitle.Name = "lblTitle"; + this.lblTitle.Size = new System.Drawing.Size(227, 19); + this.lblTitle.TabIndex = 2; + this.lblTitle.Text = "Greenshot x.x.xxx"; + // + // lblLicense + // + this.lblLicense.Location = new System.Drawing.Point(109, 34); + this.lblLicense.Name = "lblLicense"; + this.lblLicense.Size = new System.Drawing.Size(369, 68); + this.lblLicense.TabIndex = 3; + this.lblLicense.Text = "Copyright (C) 2007 Thomas Braun, Jens Klingen"; + // + // lblHost + // + this.lblHost.Location = new System.Drawing.Point(12, 109); + this.lblHost.Name = "lblHost"; + this.lblHost.Size = new System.Drawing.Size(466, 23); + this.lblHost.TabIndex = 4; + this.lblHost.Text = "Greenshot is hosted by sourceforge.net at"; + // + // linkLblLicense + // + this.linkLblLicense.Location = new System.Drawing.Point(109, 85); + this.linkLblLicense.Name = "linkLblLicense"; + this.linkLblLicense.Size = new System.Drawing.Size(369, 23); + this.linkLblLicense.TabIndex = 5; + this.linkLblLicense.TabStop = true; + this.linkLblLicense.Text = "http://www.gnu.org/licenses/gpl.html"; + this.linkLblLicense.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + // + // linkLblHost + // + this.linkLblHost.Location = new System.Drawing.Point(13, 124); + this.linkLblHost.Name = "linkLblHost"; + this.linkLblHost.Size = new System.Drawing.Size(465, 23); + this.linkLblHost.TabIndex = 6; + this.linkLblHost.TabStop = true; + this.linkLblHost.Text = "http://sourceforge.net/projects/greenshot/"; + this.linkLblHost.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + // + // linkLblBugs + // + this.linkLblBugs.Location = new System.Drawing.Point(13, 162); + this.linkLblBugs.Name = "linkLblBugs"; + this.linkLblBugs.Size = new System.Drawing.Size(465, 23); + this.linkLblBugs.TabIndex = 8; + this.linkLblBugs.TabStop = true; + this.linkLblBugs.Text = "http://sourceforge.net/tracker/?group_id=191585&atid=937972"; + this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + // + // lblBugs + // + this.lblBugs.Location = new System.Drawing.Point(12, 147); + this.lblBugs.Name = "lblBugs"; + this.lblBugs.Size = new System.Drawing.Size(466, 23); + this.lblBugs.TabIndex = 7; + this.lblBugs.Text = "Please report bugs to"; + // + // linkLblDonations + // + this.linkLblDonations.Location = new System.Drawing.Point(13, 201); + this.linkLblDonations.Name = "linkLblDonations"; + this.linkLblDonations.Size = new System.Drawing.Size(465, 23); + this.linkLblDonations.TabIndex = 10; + this.linkLblDonations.TabStop = true; + this.linkLblDonations.Text = "http://getgreenshot.org/support/"; + this.linkLblDonations.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + // + // lblDonations + // + this.lblDonations.Location = new System.Drawing.Point(12, 186); + this.lblDonations.Name = "lblDonations"; + this.lblDonations.Size = new System.Drawing.Size(466, 23); + this.lblDonations.TabIndex = 9; + this.lblDonations.Text = "If you like Greenshot, you might consider donating a dime or two at"; + // + // linkLblIcons + // + this.linkLblIcons.Location = new System.Drawing.Point(13, 239); + this.linkLblIcons.Name = "linkLblIcons"; + this.linkLblIcons.Size = new System.Drawing.Size(279, 23); + this.linkLblIcons.TabIndex = 12; + this.linkLblIcons.TabStop = true; + this.linkLblIcons.Text = "http://p.yusukekamiyamane.com"; + this.linkLblIcons.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + // + // lblIcons + // + this.lblIcons.Location = new System.Drawing.Point(12, 224); + this.lblIcons.Name = "lblIcons"; + this.lblIcons.Size = new System.Drawing.Size(466, 23); + this.lblIcons.TabIndex = 11; + this.lblIcons.Text = "Greenshot uses icons from / derived from Mark James\' splendid Silk Icon Set on"; + // + // linkLabel1 + // + this.linkLabel1.Location = new System.Drawing.Point(304, 8); + this.linkLabel1.Name = "linkLabel1"; + this.linkLabel1.Size = new System.Drawing.Size(203, 23); + this.linkLabel1.TabIndex = 13; + this.linkLabel1.TabStop = true; + this.linkLabel1.Text = "http://getgreenshot.org"; + this.linkLabel1.TextAlign = System.Drawing.ContentAlignment.TopRight; + this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + // + // pictureBox1 + // + this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); + this.pictureBox1.Location = new System.Drawing.Point(12, 12); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(90, 90); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; + this.pictureBox1.TabIndex = 14; + this.pictureBox1.TabStop = false; + // + // lblTranslation + // + this.lblTranslation.Location = new System.Drawing.Point(12, 262); + this.lblTranslation.Name = "lblTranslation"; + this.lblTranslation.Size = new System.Drawing.Size(466, 23); + this.lblTranslation.TabIndex = 15; + this.lblTranslation.Text = "English translation by YOUR_NAME"; + // + // AboutForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(519, 293); + this.Controls.Add(this.lblTranslation); + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.linkLabel1); + this.Controls.Add(this.linkLblIcons); + this.Controls.Add(this.lblIcons); + this.Controls.Add(this.linkLblDonations); + this.Controls.Add(this.lblDonations); + this.Controls.Add(this.linkLblBugs); + this.Controls.Add(this.lblBugs); + this.Controls.Add(this.linkLblHost); + this.Controls.Add(this.linkLblLicense); + this.Controls.Add(this.lblHost); + this.Controls.Add(this.lblLicense); + this.Controls.Add(this.lblTitle); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "AboutForm"; + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.Label lblTranslation; + private System.Windows.Forms.LinkLabel linkLabel1; + private System.Windows.Forms.Label lblHost; + private System.Windows.Forms.LinkLabel linkLblHost; + private System.Windows.Forms.Label lblDonations; + private System.Windows.Forms.LinkLabel linkLblDonations; + private System.Windows.Forms.Label lblBugs; + private System.Windows.Forms.LinkLabel linkLblBugs; + private System.Windows.Forms.LinkLabel linkLblLicense; + private System.Windows.Forms.LinkLabel linkLblIcons; + private System.Windows.Forms.Label lblIcons; + private System.Windows.Forms.Label lblLicense; + private System.Windows.Forms.Label lblTitle; + private System.Windows.Forms.PictureBox pictureBox1; + + void LinkLabelClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e) { + openLink((LinkLabel)sender); + } + + private void openLink(LinkLabel link) { + try { + link.LinkVisited = true; + System.Diagnostics.Process.Start(link.Text); + } catch (Exception) { + MessageBox.Show(lang.GetString(LangKey.error_openlink),lang.GetString(LangKey.error)); + } + } + } +} diff --git a/Greenshot/Forms/AboutForm.cs b/Greenshot/Forms/AboutForm.cs new file mode 100644 index 000000000..50ffb2f1a --- /dev/null +++ b/Greenshot/Forms/AboutForm.cs @@ -0,0 +1,71 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Reflection; +using System.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; + +namespace Greenshot { + /// + /// Description of AboutForm. + /// + public partial class AboutForm : Form { + private ILanguage lang; + + public AboutForm() { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + + Version v = Assembly.GetExecutingAssembly().GetName().Version; + // Format is like this: AssemblyVersion("Major.Minor.Build.Revision")] + lblTitle.Text = "Greenshot " + v.Major + "." + v.Minor + "." + v.Build + " Build " + v.Revision.ToString("0000"); + lang = Language.GetInstance(); + updateUI(); + } + + void updateUI() { + this.Text = lang.GetString(LangKey.about_title); + this.lblLicense.Text = lang.GetString(LangKey.about_license); + this.lblHost.Text = lang.GetString(LangKey.about_host); + this.lblBugs.Text = lang.GetString(LangKey.about_bugs); + this.lblDonations.Text = lang.GetString(LangKey.about_donations); + this.lblIcons.Text = lang.GetString(LangKey.about_icons); + this.lblTranslation.Text = lang.GetString(LangKey.about_translation); + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { + try { + if (msg.WParam.ToInt32() == (int)Keys.Escape) { + this.Close(); + } else { + return base.ProcessCmdKey(ref msg, keyData); + } + } catch (Exception) { + } + return base.ProcessCmdKey(ref msg,keyData); + } + } +} diff --git a/Greenshot/Forms/AboutForm.resx b/Greenshot/Forms/AboutForm.resx new file mode 100644 index 000000000..2d77e47ca --- /dev/null +++ b/Greenshot/Forms/AboutForm.resx @@ -0,0 +1,503 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + DhT/B6rDw1pTOdhMAAAAAElFTkSuQmCC + + + + + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPSkpKSisCAAAAAAAAAQAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFTg9JgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAgAAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCKAAAACAAAABA + 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 + + + \ No newline at end of file diff --git a/Greenshot/Forms/BugReportForm.Designer.cs b/Greenshot/Forms/BugReportForm.Designer.cs new file mode 100644 index 000000000..902783476 --- /dev/null +++ b/Greenshot/Forms/BugReportForm.Designer.cs @@ -0,0 +1,118 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +namespace Greenshot.Forms { + partial class BugReportForm { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BugReportForm)); + this.labelBugReportInfo = new System.Windows.Forms.Label(); + this.textBoxDescription = new System.Windows.Forms.TextBox(); + this.btnClose = new System.Windows.Forms.Button(); + this.linkLblBugs = new System.Windows.Forms.LinkLabel(); + this.SuspendLayout(); + // + // labelBugReportInfo + // + this.labelBugReportInfo.Location = new System.Drawing.Point(12, 9); + this.labelBugReportInfo.Name = "labelBugReportInfo"; + this.labelBugReportInfo.Size = new System.Drawing.Size(481, 141); + this.labelBugReportInfo.TabIndex = 0; + this.labelBugReportInfo.Text = resources.GetString("labelBugReportInfo.Text"); + // + // textBoxDescription + // + this.textBoxDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxDescription.Location = new System.Drawing.Point(12, 179); + this.textBoxDescription.Multiline = true; + this.textBoxDescription.Name = "textBoxDescription"; + this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textBoxDescription.Size = new System.Drawing.Size(504, 232); + this.textBoxDescription.TabIndex = 1; + // + // btnClose + // + this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnClose.Location = new System.Drawing.Point(377, 417); + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(139, 23); + this.btnClose.TabIndex = 2; + this.btnClose.Text = "Close"; + this.btnClose.UseVisualStyleBackColor = true; + // + // linkLblBugs + // + this.linkLblBugs.Location = new System.Drawing.Point(12, 153); + this.linkLblBugs.Name = "linkLblBugs"; + this.linkLblBugs.Size = new System.Drawing.Size(465, 23); + this.linkLblBugs.TabIndex = 9; + this.linkLblBugs.TabStop = true; + this.linkLblBugs.Text = "http://sourceforge.net/tracker/?group_id=191585&atid=937972"; + this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLblBugsLinkClicked); + // + // BugReportForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnClose; + this.ClientSize = new System.Drawing.Size(528, 452); + this.Controls.Add(this.linkLblBugs); + this.Controls.Add(this.btnClose); + this.Controls.Add(this.textBoxDescription); + this.Controls.Add(this.labelBugReportInfo); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "BugReportForm"; + this.Text = "Error"; + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.LinkLabel linkLblBugs; + private System.Windows.Forms.Button btnClose; + private System.Windows.Forms.TextBox textBoxDescription; + private System.Windows.Forms.Label labelBugReportInfo; + } +} diff --git a/Greenshot/Forms/BugReportForm.cs b/Greenshot/Forms/BugReportForm.cs new file mode 100644 index 000000000..fd165b5fa --- /dev/null +++ b/Greenshot/Forms/BugReportForm.cs @@ -0,0 +1,70 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Drawing; +using System.Net; +using System.Web; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Helpers; +using GreenshotPlugin.Core; + +namespace Greenshot.Forms { + public partial class BugReportForm : Form { + private ILanguage lang; + private BugReportForm() { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + lang = Language.GetInstance(); + UpdateUI(); + } + + + public BugReportForm(string bugText) { + InitializeComponent(); + lang = Language.GetInstance(); + UpdateUI(); + this.textBoxDescription.Text = bugText; + } + + void UpdateUI() { + this.Text = lang.GetString(LangKey.bugreport_title); + this.labelBugReportInfo.Text = lang.GetString(LangKey.bugreport_info); + this.btnClose.Text = lang.GetString(LangKey.bugreport_cancel); + } + + void LinkLblBugsLinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e) { + openLink((LinkLabel)sender); + } + + private void openLink(LinkLabel link) { + try { + link.LinkVisited = true; + System.Diagnostics.Process.Start(link.Text); + } catch (Exception) { + MessageBox.Show(lang.GetString(LangKey.error_openlink),lang.GetString(LangKey.error)); + } + } + } +} diff --git a/Greenshot/Forms/BugReportForm.resx b/Greenshot/Forms/BugReportForm.resx new file mode 100644 index 000000000..489a8d3e9 --- /dev/null +++ b/Greenshot/Forms/BugReportForm.resx @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Sorry, an unexpected error occured. + +The good news is: you can help us getting rid of it by filing a bug report. +Please visit the URL below, create a new bug report and paste the contents from the text area into the description. +Also, we would highly appreciate if you could add a short description about the circumstances under which the error occurred. + + + + + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPSkpKSisCAAAAAAAAAQAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFTg9JgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAgAAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCKAAAACAAAABA + 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 + + + \ No newline at end of file diff --git a/Greenshot/Forms/CaptureForm.Designer.cs b/Greenshot/Forms/CaptureForm.Designer.cs new file mode 100644 index 000000000..d71ed66b3 --- /dev/null +++ b/Greenshot/Forms/CaptureForm.Designer.cs @@ -0,0 +1,84 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +namespace Greenshot.Forms { + partial class CaptureForm { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.Windows.Forms.PictureBox pictureBox; + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() { + this.pictureBox = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox + // + this.pictureBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.pictureBox.Location = new System.Drawing.Point(0, 0); + this.pictureBox.Name = "pictureBox"; + this.pictureBox.Size = new System.Drawing.Size(0, 0); + this.pictureBox.TabIndex = 1; + this.pictureBox.TabStop = false; + this.pictureBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBoxMouseMove); + this.pictureBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PictureBoxMouseDown); + this.pictureBox.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBoxPaint); + this.pictureBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.PictureBoxMouseUp); + // + // CaptureForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(0, 0); + this.Controls.Add(this.pictureBox); + this.Cursor = System.Windows.Forms.Cursors.Cross; + this.DoubleBuffered = true; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Name = "CaptureForm"; + this.ShowInTaskbar = false; + this.TopMost = true; + this.VisibleChanged += new System.EventHandler(this.CaptureFormVisibleChanged); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.CaptureFormKeyDown); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit(); + this.Visible = false; + this.ResumeLayout(false); + } + } +} diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs new file mode 100644 index 000000000..2820ef44a --- /dev/null +++ b/Greenshot/Forms/CaptureForm.cs @@ -0,0 +1,826 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Drawing.Printing; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Drawing; +using Greenshot.Helpers; +using Greenshot.Plugin; +using Greenshot.UnmanagedHelpers; +using GreenshotPlugin.Core; + +namespace Greenshot.Forms { + /// + /// Description of CaptureForm. + /// + public partial class CaptureForm : Form, ICaptureHost { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(CaptureForm)); + + private int mX; + private int mY; + private Point cursorPos = Point.Empty; + // TODO: dispose Brush & Pen, not very important as we only instanciate this once + private Brush OverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); + private Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); + private CaptureMode captureMode = CaptureMode.None; + private List windows = new List(); + private WindowDetails selectedCaptureWindow; + private bool mouseDown = false; + private Rectangle captureRect = Rectangle.Empty; + private ICapture capture = null; + private AppConfig conf = AppConfig.GetInstance(); + private CopyData copyData = null; + private ILanguage lang = Language.GetInstance(); + + public CaptureForm() { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + // Create a new instance of the class: copyData = new CopyData(); + copyData = new CopyData(); + + // Assign the handle: + copyData.AssignHandle(this.Handle); + // Create the channel to send on: + copyData.Channels.Add("Greenshot"); + // Hook up received event: + copyData.DataReceived += new DataReceivedEventHandler(CopyDataDataReceived); + + // Make sure the form is hidden (might be overdoing it...) + this.Hide(); + } + + /// + /// DataReceivedEventHandler + /// + /// + /// + private void CopyDataDataReceived(object sender, DataReceivedEventArgs dataReceivedEventArgs) { + // Cast the data to the type of object we sent: + DataTransport dataTransport = (DataTransport)dataReceivedEventArgs.Data; + HandleDataTransport(dataTransport); + } + + public void HandleDataTransport(DataTransport dataTransport) { + LOG.Debug("Data received, Command = " + dataTransport.Command + ", Data: " + dataTransport.CommandData); + switch(dataTransport.Command) { + case CommandEnum.Exit: + Application.Exit(); + break; + case CommandEnum.ReloadConfig: + AppConfig.Reload(); + // Even update language when needed + MainForm.instance.UpdateUI(); + break; + case CommandEnum.OpenFile: + string filename = dataTransport.CommandData; + if (File.Exists(filename)) { + MakeCapture(filename); + } else { + LOG.Warn("No such file: " + filename); + } + break; + default: + LOG.Error("Unknown command!"); + break; + } + } + + void DoCaptureFeedback() { + if((bool)conf.Ui_Effects_CameraSound) { + SoundHelper.Play(); + } + if((bool)conf.Ui_Effects_Flashlight) { + FlashlightForm flashlightForm = new FlashlightForm(); + flashlightForm.Bounds = capture.ScreenBounds; + flashlightForm.FadeIn(); + flashlightForm.FadeOut(); + flashlightForm.Dispose(); + } + } + + /// + /// Make Capture with default destinations + /// + /// CaptureMode + /// bool false if the mouse should not be captured, true if the configuration should be checked + public void MakeCapture(CaptureMode mode, bool captureMouseCursor) { + Capture passingCapture = new Capture(); + MakeCapture(mode, captureMouseCursor, passingCapture); + } + + /// + /// Make Capture with default destinations + /// + /// CaptureMode + /// bool false if the mouse should not be captured, true if the configuration should be checked + public void MakeCapture(CaptureMode mode, bool captureMouseCursor, CaptureHandler captureHandler) { + Capture passingCapture = new Capture(); + passingCapture.CaptureDetails.CaptureHandler = captureHandler; + MakeCapture(mode, captureMouseCursor, passingCapture); + } + + + /// + /// Make Capture with specified destinations + /// + /// CaptureMode + /// bool false if the mouse should not be captured, true if the configuration should be checked + /// List with destinations + public void MakeCapture(CaptureMode mode, bool captureMouseCursor, List captureDestinations) { + Capture passingCapture = new Capture(); + passingCapture.CaptureDetails.CaptureDestinations = captureDestinations; + MakeCapture(mode, captureMouseCursor, passingCapture); + } + + /// + /// Make Capture with file name + /// + /// List with destinations + public void MakeCapture(string filename) { + Capture passingCapture = new Capture(); + passingCapture.CaptureDetails.Filename = filename; + MakeCapture(CaptureMode.File, false, passingCapture); + } + + /// + /// Make Capture with specified destinations + /// + /// CaptureMode + /// bool false if the mouse should not be captured, true if the configuration should be checked + /// List with destinations + private void MakeCapture(CaptureMode mode, bool captureMouseCursor, ICapture newCapture) { + if (captureMode != CaptureMode.None) { + LOG.Warn(String.Format("Capture started while capturing, current mode = {0} new capture was {1}.", captureMode, mode)); + return; + } else { + LOG.Debug(String.Format("MakeCapture({0}, {1})", mode, captureMouseCursor)); + } + captureMode = mode; + + // cleanup the previos information if there is still any + if (capture != null) { + LOG.Debug("Capture wasn't disposed yet, this would suggest a leak"); + capture.Dispose(); + capture = null; + } + + // Use the supplied Capture information + capture = newCapture; + capture.CaptureDetails.CaptureMode = mode; + + // Delay for the Context menu + System.Threading.Thread.Sleep(conf.Capture_Wait_Time); + + // Allways capture Mousecursor, only show when needed + capture = WindowCapture.CaptureCursor(capture); + capture.CursorVisible = false; + // Check if needed + if (captureMouseCursor && mode != CaptureMode.Clipboard && mode != CaptureMode.File) { + capture.CursorVisible = (conf.Capture_Mousepointer.HasValue && conf.Capture_Mousepointer.Value); + } + + switch(mode) { + case CaptureMode.Window: + capture = WindowCapture.CaptureScreen(capture); + CaptureWithFeedback(); + break; + case CaptureMode.ActiveWindow: + CaptureActiveWindow(); + finishCapture(); + break; + case CaptureMode.FullScreen: + capture = WindowCapture.CaptureScreen(capture); + HandleCapture(); + break; + case CaptureMode.Clipboard: + Image clipboardImage = null; + string text = "Clipboard"; + if (Clipboard.ContainsImage()) { + clipboardImage = Clipboard.GetImage(); + } else if (ClipboardHelper.GetFormats().Contains("HTML Format")) { + HtmlFragment htmlFragment = HtmlFragment.FromClipboard(); + text = htmlFragment.Fragment; + clipboardImage = WebsiteImageGenerator.GetImageFromHTML(text); + } else { + text = Clipboard.GetText(); + if ((text != null && text.StartsWith("http://"))) { + clipboardImage = WebsiteImageGenerator.GetImageFromURL(text); + } + } + if (clipboardImage != null) { + if (capture != null) { + capture.Image = clipboardImage; + } else { + capture = new Capture(clipboardImage); + } + // Force Editor + capture.CaptureDetails.AddDestination(CaptureDestination.Editor); + HandleCapture(); + } else { + MessageBox.Show("Couldn't create bitmap from : " + text); + } + break; + case CaptureMode.File: + Bitmap fileBitmap = null; + try { + fileBitmap = new Bitmap(capture.CaptureDetails.Filename, true); + } catch (Exception e) { + LOG.Error(e.Message, e); + MessageBox.Show(lang.GetFormattedString(LangKey.error_openfile, capture.CaptureDetails.Filename)); + } + if (fileBitmap != null) { + if (capture != null) { + capture.Image = fileBitmap; + } else { + capture = new Capture(fileBitmap); + } + // Force Editor + capture.CaptureDetails.AddDestination(CaptureDestination.Editor); + HandleCapture(); + } + break; + case CaptureMode.LastRegion: + if (!RuntimeConfig.LastCapturedRegion.Equals(Rectangle.Empty)) { + capture = WindowCapture.CaptureRectangle(capture, RuntimeConfig.LastCapturedRegion); + HandleCapture(); + } + break; + case CaptureMode.Region: + capture = WindowCapture.CaptureScreen(capture); + CaptureWithFeedback(); + break; + default: + LOG.Warn("Unknown capture mode: " + mode); + break; + } + } + + private ICapture AddConfiguredDestination(ICapture capture) { + if ((conf.Output_Destinations & ScreenshotDestinations.FileDefault) == ScreenshotDestinations.FileDefault) { + capture.CaptureDetails.AddDestination(CaptureDestination.File); + } + + if ((conf.Output_Destinations & ScreenshotDestinations.FileWithDialog) == ScreenshotDestinations.FileWithDialog) { + capture.CaptureDetails.AddDestination(CaptureDestination.FileWithDialog); + } + + if ((conf.Output_Destinations & ScreenshotDestinations.Clipboard) == ScreenshotDestinations.Clipboard) { + capture.CaptureDetails.AddDestination(CaptureDestination.Clipboard); + } + + if ((conf.Output_Destinations & ScreenshotDestinations.Printer) == ScreenshotDestinations.Printer) { + capture.CaptureDetails.AddDestination(CaptureDestination.Printer); + } + + if ((conf.Output_Destinations & ScreenshotDestinations.Editor) == ScreenshotDestinations.Editor) { + capture.CaptureDetails.AddDestination(CaptureDestination.Editor); + } + + if ((conf.Output_Destinations & ScreenshotDestinations.EMail) == ScreenshotDestinations.EMail) { + capture.CaptureDetails.AddDestination(CaptureDestination.EMail); + } + return capture; + } + + /// + /// Process a bitmap like it was captured + /// + /// The bitmap to process + public void HandleCapture(Bitmap bitmap) { + Capture capture = new Capture(bitmap); + HandleCapture(capture); + } + + // This is also an ICapture Interface implementation + public void HandleCapture(Capture capture) { + this.capture = capture; + HandleCapture(); + } + + private void HandleCapture() { + string fullPath = null; + // Flag to see if the image was "exported" so the FileEditor doesn't + // ask to save the file as long as nothing is done. + bool outputMade = false; + + // Make sure the user sees that the capture is made + if (capture.CaptureDetails.CaptureMode != CaptureMode.File && capture.CaptureDetails.CaptureMode != CaptureMode.Clipboard) { + DoCaptureFeedback(); + } else { + // If File || Clipboard + // Maybe not "made" but the original is still there... somehow + outputMade = true; + } + + LOG.Debug("A capture of: " + capture.CaptureDetails.Title); + + // Create event OnCaptureTaken for all Plugins + PluginHelper.instance.CreateCaptureTakenEvent(capture); + + // check if someone has passed a handler + if (capture.CaptureDetails.CaptureHandler != null) { + CaptureTakenEventArgs eventArgs = new CaptureTakenEventArgs(capture); + capture.CaptureDetails.CaptureHandler(this, eventArgs); + } else if (capture.CaptureDetails.CaptureDestinations == null || capture.CaptureDetails.CaptureDestinations.Count == 0) { + AddConfiguredDestination(capture); + } + + // Create Surface with capture, this way elements can be added automatically (like the mouse cursor) + Surface surface = new Surface(capture); + + // Call plugins to do something with the screenshot + PluginHelper.instance.CreateSurfaceFromCaptureEvent(capture, surface); + + // Disable capturing + captureMode = CaptureMode.None; + + // Retrieve important information from the Capture object + ICaptureDetails captureDetails = capture.CaptureDetails; + List captureDestinations = capture.CaptureDetails.CaptureDestinations; + + // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). + capture.Dispose(); + capture = null; + + // Want to add more stuff to the surface?? DO IT HERE! + + // Create Image for writing/printing etc and use "using" as all code paths either output the image or copy the image + using (Image image = surface.GetImageForExport()) { + // Flag to detect if we need to create a temp file for the email + // or use the file that was written + bool fileWritten = false; + if (captureDestinations.Contains(CaptureDestination.File)) { + string filename = FilenameHelper.GetFilenameFromPattern(conf.Output_File_FilenamePattern, conf.Output_File_Format, captureDetails); + fullPath = Path.Combine(conf.Output_File_Path,filename); + + // 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(image, fullPath, captureDetails); + fileWritten = true; + outputMade = true; + } catch (Exception e) { + LOG.Error("Error saving screenshot!", e); + // Show the problem + MessageBox.Show(lang.GetString(LangKey.error_save), lang.GetString(LangKey.error)); + // when save failed we present a SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(image, captureDetails); + fileWritten = (fullPath != null); + } + } + + if (captureDestinations.Contains(CaptureDestination.FileWithDialog)) { + fullPath = ImageOutput.SaveWithDialog(image, captureDetails); + fileWritten = (fullPath != null); + outputMade = outputMade || fileWritten; + } + + if (captureDestinations.Contains(CaptureDestination.Clipboard)) { + ClipboardHelper.SetClipboardData(image); + outputMade = true; + } + + if (captureDestinations.Contains(CaptureDestination.Printer)) { + PrinterSettings printerSettings = new PrintHelper(image, captureDetails).PrintWithDialog(); + outputMade = outputMade || printerSettings != null; + } + + if (captureDestinations.Contains(CaptureDestination.EMail)) { + if (!fileWritten) { + MapiMailMessage.SendImage(image, captureDetails); + } else { + MapiMailMessage.SendImage(fullPath, captureDetails.Title, false); + } + // Don't know how to handle a cancel in the email + outputMade = true; + } + } + + // If the editor is opened, let it Dispose the surface! + if (captureDestinations.Contains(CaptureDestination.Editor)) { + ImageEditorForm editor = new ImageEditorForm(surface, outputMade); + + if (fullPath != null) { + editor.SetImagePath(fullPath); + } + editor.Show(); + editor.Activate(); + LOG.Debug("Finished opening Editor"); + } else { + // Dispose the surface, we are done with it! + surface.Dispose(); + } + + // Make CaptureForm invisible + this.Visible = false; + // Hiding makes the editor (if any) get focus + this.Hide(); + } + + /** + * Finishing the whole Capture with Feedback flow, passing the result on to the HandleCapture + */ + private void finishCapture() { + bool fromWindow = (conf.Capture_Complete_Window.HasValue && conf.Capture_Complete_Window.Value); + + // Get title + if (selectedCaptureWindow != null) { + if (capture == null) { + capture = new Capture(); + } + capture.CaptureDetails.Title = selectedCaptureWindow.Text; + } + + if ( (captureMode == CaptureMode.Window || captureMode == CaptureMode.ActiveWindow) && selectedCaptureWindow != null) { + Image capturedWindowImage = null; + // What type of capturing? (From Screen or from window) + if (fromWindow) { + // "Capture" the windows content + capturedWindowImage = selectedCaptureWindow.Image; + if (capturedWindowImage != null) { + // Fix Cursor location as we don't crop + capture.MoveMouseLocation(-selectedCaptureWindow.Rectangle.Location.X, -selectedCaptureWindow.Rectangle.Location.Y); + // Set the image + capture.Image = capturedWindowImage; + } + } + // If the PrintWindow implementation isn't used or failed we use the image from the screen. + if (capturedWindowImage == null) { + // From screen, take the location of the selected window to copy the content + captureRect = selectedCaptureWindow.Rectangle; + // Cropping capture to the selected rectangle + capture.CropWithScreenCoordinates(captureRect); + // save for re-capturing later and show recapture context menu option + RuntimeConfig.LastCapturedRegion = captureRect; + } + StopCapturing(false); + HandleCapture(); + } else if (captureRect.Height > 0 && captureRect.Width > 0) { + // Resizing the captured rectangle (no need to make another capture + capture.CropWithScreenCoordinates(captureRect); + // save for re-capturing later and show recapture context menu option + RuntimeConfig.LastCapturedRegion = captureRect; + + StopCapturing(false); + HandleCapture(); + } + } + + /** + * Stopping the whole Capture with Feedback flow + */ + private void StopCapturing(bool cleanupCapture) { + mouseDown = false; + // Disable the capture mode + captureMode = CaptureMode.None; + cursorPos.X = 0; + cursorPos.Y = 0; + selectedCaptureWindow = null; + if (cleanupCapture && capture != null) { + capture.Dispose(); + capture = null; + } + this.Hide(); + } + + #region key handling + void CaptureFormKeyDown(object sender, KeyEventArgs e) { + if (e.KeyCode == Keys.Escape) { + StopCapturing(true); + } else if (e.KeyCode == Keys.M) { + // Toggle mouse cursor + capture.CursorVisible = !capture.CursorVisible; + PictureBoxMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); + } else if (e.KeyCode == Keys.PageDown) { + // Extend the selectable rectangles with the "insides" of the current Window + if (captureMode == CaptureMode.Window) { + WindowDetails currentWindow = FindCurrentWindow(); + if (currentWindow != null && !currentWindow.HasChildren) { + currentWindow.GetChildren(); + } else { + LOG.Warn("No window found!!"); + } + } + PictureBoxMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); + } else if (e.KeyCode == Keys.Space) { + switch (captureMode) { + case CaptureMode.Region: + captureMode = CaptureMode.Window; + break; + case CaptureMode.Window: + captureMode = CaptureMode.Region; + break; + } + PictureBoxMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); + } else if (e.KeyCode == Keys.Return && captureMode == CaptureMode.Window) { + finishCapture(); + } + } + #endregion + + private void CaptureActiveWindow() { + LOG.Debug("CaptureActiveWindow"); + IntPtr hWnd = User32.GetForegroundWindow(); + if (hWnd != null && hWnd != IntPtr.Zero) { + // Make sure the screen is captured in case of errors or if we don't do direct window capturing + capture = WindowCapture.CaptureScreen(capture); + selectedCaptureWindow = new WindowDetails(hWnd); + // Content only + if ((conf.Capture_Window_Content.HasValue && conf.Capture_Window_Content.Value)) { + // Print Tree for debugging + selectedCaptureWindow.PrintTree(""); + WindowDetails contentWindow = selectedCaptureWindow.GetContent(); + if (contentWindow != null) { + selectedCaptureWindow = contentWindow; + } + } + } + } + + #region capture with feedback + private void CaptureWithFeedback() { + windows.Clear(); + // Start Enumeration of "active" windows + WindowsEnumerator windowsEnumerator = new WindowsEnumerator(); + windowsEnumerator.GetWindows(); + foreach(WindowDetails window in windowsEnumerator.Items) { + // Window should be visible and not ourselves + if (window.Visible && !window.Handle.Equals(this.Handle)) { + windows.Add(window); + } + } + + this.SuspendLayout(); + this.Bounds = capture.ScreenBounds; + pictureBox.Image = capture.Image; + this.Visible = true; + this.ResumeLayout(); + this.Focus(); + this.Show(); + } + + /// + /// Helper Method for finding the current Window in the available rectangles + /// + /// WindowDetails + private WindowDetails FindCurrentWindow() { + foreach(WindowDetails window in windows) { + Rectangle windowRectangle = window.Rectangle; + if (windowRectangle.Contains(Cursor.Position)) { + WindowDetails selectedChild = null; + // Content only + if ((conf.Capture_Window_Content.HasValue && conf.Capture_Window_Content.Value)) { + WindowDetails childWindow = window.GetContent(); + if (childWindow != null && childWindow.Rectangle.Contains(Cursor.Position)) { + return childWindow; + } + } + // Check if Children need to be parsed (only if "pgdn" was used) + if (window.HasChildren) { + foreach(WindowDetails childWindow in window.Children) { + windowRectangle = childWindow.Rectangle; + if (windowRectangle.Contains(Cursor.Position)) { + if (selectedChild == null) { + selectedChild = childWindow; + } else { + int sizeCurrent = childWindow.Rectangle.Height * childWindow.Rectangle.Width; + int sizeSelected = selectedChild.Rectangle.Height * selectedChild.Rectangle.Width; + if (sizeCurrent < sizeSelected) { + selectedChild = childWindow; + } + } + } + } + if (selectedChild != null) { + return selectedChild; + } + } + return window; + } + } + return null; + } + #endregion + + #region pictureBox events + void PictureBoxMouseDown(object sender, MouseEventArgs e) { + if (e.Button == MouseButtons.Left) { + mX = e.X; + mY = e.Y; + mouseDown = true; + PictureBoxMouseMove(this, e); + } + } + + void PictureBoxMouseUp(object sender, MouseEventArgs e) { + if (mouseDown) { + // 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 + finishCapture(); + } else if (captureRect.Height > 0 && captureRect.Width > 0) { + // correct the GUI width to real width if Region mode + if (captureMode == CaptureMode.Region) { + captureRect.Width += 1; + captureRect.Height += 1; + } + // Go and process the capture + finishCapture(); + } + } + } + + void PictureBoxMouseMove(object sender, MouseEventArgs e) { + cursorPos.X = e.X; + cursorPos.Y = e.Y; + + if (captureMode == CaptureMode.Region && mouseDown) { + captureRect = GuiRectangle.GetGuiRectangle(e.X + this.Left, e.Y + this.Top, mX - e.X, mY - e.Y); + } + + // Iterate over the found windows and check if the current location is inside a window + selectedCaptureWindow = FindCurrentWindow(); + if (selectedCaptureWindow != null) { + if (capture == null) { + capture = new Capture(); + } + capture.CaptureDetails.Title = selectedCaptureWindow.Text; + if (captureMode == CaptureMode.Window) { + captureRect = selectedCaptureWindow.Rectangle; + } + } + + pictureBox.Invalidate(); + } + + void PictureBoxPaint(object sender, PaintEventArgs e) { + Graphics graphics = e.Graphics; + + if (capture.Cursor != null && capture.CursorVisible) { + graphics.DrawIcon(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y); + } + + if (mouseDown || captureMode == CaptureMode.Window) { + Rectangle screenbounds = capture.ScreenBounds; + captureRect.Intersect(screenbounds); // crop what is outside the screen + Rectangle fixedRect = new Rectangle( captureRect.X, captureRect.Y, captureRect.Width, captureRect.Height ); + fixedRect.X += Math.Abs( screenbounds.X ); + fixedRect.Y += Math.Abs( screenbounds.Y ); + + graphics.FillRectangle( OverlayBrush, fixedRect ); + graphics.DrawRectangle( OverlayPen, fixedRect ); + + // rulers + int dist = 8; + + using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { + int hSpace = TextRenderer.MeasureText(captureRect.Width.ToString(), rulerFont).Width + 3; + int vSpace = TextRenderer.MeasureText(captureRect.Height.ToString(), rulerFont).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 = Drawing.RoundedRectangle.Create2( + fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, + fixedRect.Y - dist - 7, + TextRenderer.MeasureText(captureRect.Width.ToString(), rulerFont).Width - 3, + TextRenderer.MeasureText(captureRect.Width.ToString(), rulerFont).Height, + 3)) { + graphics.FillPath(bgBrush, p); + graphics.DrawPath(rulerPen, p); + graphics.DrawString(captureRect.Width.ToString(), 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 = Drawing.RoundedRectangle.Create2( + fixedRect.X - (TextRenderer.MeasureText(captureRect.Height.ToString(), rulerFont).Width) + 1, + fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, + TextRenderer.MeasureText(captureRect.Height.ToString(), rulerFont).Width - 3, + TextRenderer.MeasureText(captureRect.Height.ToString(), rulerFont).Height - 1, + 3)) { + graphics.FillPath(bgBrush, p); + graphics.DrawPath(rulerPen, p); + graphics.DrawString(captureRect.Height.ToString(), rulerFont, rulerPen.Brush, fixedRect.X - (TextRenderer.MeasureText(captureRect.Height.ToString(), rulerFont).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 = null; + if (captureMode == CaptureMode.Region) { + // 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) - (TextRenderer.MeasureText(sizeText, sizeFont).Width / 2), fixedRect.Y + (captureRect.Height / 2) - (sizeFont.GetHeight() / 2)); + graphics.DrawString(sizeText, sizeFont, Brushes.LightSeaGreen, sizeLocation); + } + } + } + } else { + if (cursorPos.X > 0 || cursorPos.Y > 0) { + 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.ToString() + " x " + cursorPos.Y.ToString(); + using (Font f = new Font(FontFamily.GenericSansSerif, 8)) { + using (GraphicsPath gp = Drawing.RoundedRectangle.Create2( + cursorPos.X + 5, + cursorPos.Y + 5, + TextRenderer.MeasureText(xy, f).Width - 3, + TextRenderer.MeasureText(xy, f).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); + } + } + } + } + } + } + #endregion + + #region Form Events + private void CaptureFormVisibleChanged( object sender, EventArgs e ) { + if ( !this.Visible && pictureBox.Image != null ) { + Image img = pictureBox.Image; + pictureBox.Image = null; + img.Dispose(); + } + } + #endregion + } +} diff --git a/Greenshot/Forms/ColorDialog.Designer.cs b/Greenshot/Forms/ColorDialog.Designer.cs new file mode 100644 index 000000000..018140920 --- /dev/null +++ b/Greenshot/Forms/ColorDialog.Designer.cs @@ -0,0 +1,259 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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 . + */ +namespace Greenshot { + partial class ColorDialog : System.Windows.Forms.Form { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.btnTransparent = new System.Windows.Forms.Button(); + this.colorPanel = new System.Windows.Forms.Panel(); + this.labelHtmlColor = new System.Windows.Forms.Label(); + this.textBoxHtmlColor = new System.Windows.Forms.TextBox(); + this.labelRed = new System.Windows.Forms.Label(); + this.labelGreen = new System.Windows.Forms.Label(); + this.labelBlue = new System.Windows.Forms.Label(); + this.textBoxRed = new System.Windows.Forms.TextBox(); + this.textBoxGreen = new System.Windows.Forms.TextBox(); + this.textBoxBlue = new System.Windows.Forms.TextBox(); + this.labelRecentColors = new System.Windows.Forms.Label(); + this.textBoxAlpha = new System.Windows.Forms.TextBox(); + this.labelAlpha = new System.Windows.Forms.Label(); + this.btnApply = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnTransparent + // + this.btnTransparent.BackColor = System.Drawing.Color.Transparent; + this.btnTransparent.Location = new System.Drawing.Point(210, 4); + this.btnTransparent.Name = "btnTransparent"; + this.btnTransparent.Size = new System.Drawing.Size(78, 23); + this.btnTransparent.TabIndex = 0; + this.btnTransparent.TabStop = false; + this.btnTransparent.Text = "Transparent"; + this.btnTransparent.UseVisualStyleBackColor = false; + this.btnTransparent.Click += new System.EventHandler(this.btnTransparentClick); + // + // colorPanel + // + this.colorPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.colorPanel.Location = new System.Drawing.Point(210, 31); + this.colorPanel.Name = "colorPanel"; + this.colorPanel.Size = new System.Drawing.Size(78, 23); + this.colorPanel.TabIndex = 1; + // + // labelHtmlColor + // + this.labelHtmlColor.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World); + this.labelHtmlColor.Location = new System.Drawing.Point(210, 57); + this.labelHtmlColor.Name = "labelHtmlColor"; + this.labelHtmlColor.Size = new System.Drawing.Size(78, 17); + this.labelHtmlColor.TabIndex = 2; + this.labelHtmlColor.Text = "HTML color"; + // + // textBoxHtmlColor + // + this.textBoxHtmlColor.Location = new System.Drawing.Point(210, 71); + this.textBoxHtmlColor.Name = "textBoxHtmlColor"; + this.textBoxHtmlColor.Size = new System.Drawing.Size(78, 20); + this.textBoxHtmlColor.TabIndex = 1; + this.textBoxHtmlColor.Click += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxHtmlColor.GotFocus += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxHtmlColor.TextChanged += new System.EventHandler(this.TextBoxHexadecimalTextChanged); + this.textBoxHtmlColor.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown); + // + // labelRed + // + this.labelRed.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World); + this.labelRed.Location = new System.Drawing.Point(210, 98); + this.labelRed.Name = "labelRed"; + this.labelRed.Size = new System.Drawing.Size(78, 18); + this.labelRed.TabIndex = 4; + this.labelRed.Text = "Red"; + // + // labelGreen + // + this.labelGreen.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World); + this.labelGreen.Location = new System.Drawing.Point(210, 122); + this.labelGreen.Name = "labelGreen"; + this.labelGreen.Size = new System.Drawing.Size(78, 18); + this.labelGreen.TabIndex = 5; + this.labelGreen.Text = "Green"; + // + // labelBlue + // + this.labelBlue.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World); + this.labelBlue.Location = new System.Drawing.Point(210, 146); + this.labelBlue.Name = "labelBlue"; + this.labelBlue.Size = new System.Drawing.Size(78, 18); + this.labelBlue.TabIndex = 6; + this.labelBlue.Text = "Blue"; + // + // textBoxRed + // + this.textBoxRed.Location = new System.Drawing.Point(258, 95); + this.textBoxRed.Name = "textBoxRed"; + this.textBoxRed.Size = new System.Drawing.Size(30, 20); + this.textBoxRed.TabIndex = 2; + this.textBoxRed.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.textBoxRed.Click += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxRed.GotFocus += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxRed.TextChanged += new System.EventHandler(this.TextBoxRGBTextChanged); + this.textBoxRed.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown); + // + // textBoxGreen + // + this.textBoxGreen.Location = new System.Drawing.Point(258, 119); + this.textBoxGreen.Name = "textBoxGreen"; + this.textBoxGreen.Size = new System.Drawing.Size(30, 20); + this.textBoxGreen.TabIndex = 3; + this.textBoxGreen.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.textBoxGreen.Click += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxGreen.GotFocus += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxGreen.TextChanged += new System.EventHandler(this.TextBoxRGBTextChanged); + this.textBoxGreen.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown); + // + // textBoxBlue + // + this.textBoxBlue.Location = new System.Drawing.Point(258, 143); + this.textBoxBlue.Name = "textBoxBlue"; + this.textBoxBlue.Size = new System.Drawing.Size(30, 20); + this.textBoxBlue.TabIndex = 4; + this.textBoxBlue.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.textBoxBlue.Click += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxBlue.GotFocus += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxBlue.TextChanged += new System.EventHandler(this.TextBoxRGBTextChanged); + this.textBoxBlue.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown); + // + // labelRecentColors + // + this.labelRecentColors.Location = new System.Drawing.Point(3, 175); + this.labelRecentColors.Name = "labelRecentColors"; + this.labelRecentColors.Size = new System.Drawing.Size(148, 13); + this.labelRecentColors.TabIndex = 10; + this.labelRecentColors.Text = "Recently used colors"; + // + // textBoxAlpha + // + this.textBoxAlpha.Location = new System.Drawing.Point(258, 167); + this.textBoxAlpha.Name = "textBoxAlpha"; + this.textBoxAlpha.Size = new System.Drawing.Size(30, 20); + this.textBoxAlpha.TabIndex = 5; + this.textBoxAlpha.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.textBoxAlpha.Click += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxAlpha.GotFocus += new System.EventHandler(this.TextBoxGotFocus); + this.textBoxAlpha.TextChanged += new System.EventHandler(this.TextBoxRGBTextChanged); + this.textBoxAlpha.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxKeyDown); + // + // labelAlpha + // + this.labelAlpha.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World); + this.labelAlpha.Location = new System.Drawing.Point(210, 170); + this.labelAlpha.Name = "labelAlpha"; + this.labelAlpha.Size = new System.Drawing.Size(78, 18); + this.labelAlpha.TabIndex = 11; + this.labelAlpha.Text = "Alpha"; + // + // btnApply + // + this.btnApply.BackColor = System.Drawing.Color.Transparent; + this.btnApply.Location = new System.Drawing.Point(210, 191); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(78, 23); + this.btnApply.TabIndex = 12; + this.btnApply.TabStop = false; + this.btnApply.Text = "Apply"; + this.btnApply.UseVisualStyleBackColor = false; + this.btnApply.Click += new System.EventHandler(this.BtnApplyClick); + // + // ColorDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(292, 218); + this.Controls.Add(this.btnApply); + this.Controls.Add(this.textBoxAlpha); + this.Controls.Add(this.labelAlpha); + this.Controls.Add(this.labelRecentColors); + this.Controls.Add(this.textBoxBlue); + this.Controls.Add(this.textBoxGreen); + this.Controls.Add(this.textBoxRed); + this.Controls.Add(this.labelBlue); + this.Controls.Add(this.labelGreen); + this.Controls.Add(this.labelRed); + this.Controls.Add(this.textBoxHtmlColor); + this.Controls.Add(this.labelHtmlColor); + this.Controls.Add(this.colorPanel); + this.Controls.Add(this.btnTransparent); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ColorDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.Text = "TestProject"; + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.Label labelRed; + private System.Windows.Forms.Label labelGreen; + private System.Windows.Forms.Label labelBlue; + private System.Windows.Forms.TextBox textBoxHtmlColor; + private System.Windows.Forms.Label labelRecentColors; + private System.Windows.Forms.Label labelAlpha; + private System.Windows.Forms.Label labelHtmlColor; + private System.Windows.Forms.Button btnApply; + private System.Windows.Forms.TextBox textBoxAlpha; + private System.Windows.Forms.TextBox textBoxRed; + private System.Windows.Forms.TextBox textBoxGreen; + private System.Windows.Forms.TextBox textBoxBlue; + private System.Windows.Forms.Panel colorPanel; + private System.Windows.Forms.Button btnTransparent; + + + + + + } +} diff --git a/Greenshot/Forms/ColorDialog.cs b/Greenshot/Forms/ColorDialog.cs new file mode 100644 index 000000000..08f4ff8c7 --- /dev/null +++ b/Greenshot/Forms/ColorDialog.cs @@ -0,0 +1,242 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2010 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; + +namespace Greenshot { + /// + /// Description of ColorDialog. + /// + public partial class ColorDialog { + private static ColorDialog uniqueInstance; + + private ColorDialog() { + this.SuspendLayout(); + InitializeComponent(); + lang = Language.GetInstance(); + updateUI(); + this.SuspendLayout(); + this.createColorPalette(5,5,15,15); + this.createLastUsedColorButtonRow(5,190,15,15); + this.ResumeLayout(); + } + + public static ColorDialog GetInstance() { + if(uniqueInstance == null) { + uniqueInstance = new ColorDialog(); + } + return uniqueInstance; + } + + private ILanguage lang; + private List