diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index f4ab733e7..2bb917d9d 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -34,12 +34,13 @@ using Greenshot.Plugin; using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.Core; using Greenshot.IniFile; +using GreenshotPlugin.Controls; namespace Greenshot.Forms { /// /// The capture form is used to select a part of the capture /// - public partial class CaptureForm : Form { + public partial class CaptureForm : AnimatingForm { private enum FixMode {None, Initiated, Horizontal, Vertical}; private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(CaptureForm)); @@ -49,8 +50,10 @@ namespace Greenshot.Forms { private static Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); private static CaptureForm currentForm = null; private static Brush backgroundBrush = null; - private static int vRefresh = 0; + /// + /// Initialize the background brush + /// static CaptureForm() { Image backgroundForTransparency = GreenshotPlugin.Core.GreenshotResources.getImage("Checkerboard.Image"); backgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); @@ -67,49 +70,11 @@ namespace Greenshot.Forms { private Rectangle captureRect = Rectangle.Empty; private ICapture capture = null; private Image capturedImage = null; - private Timer timer = null; private Point previousMousePos = Point.Empty; private FixMode fixMode = FixMode.None; private RectangleAnimator windowAnimator = null; private RectangleAnimator zoomAnimator = null; - /// - /// Vertical Refresh Rate - /// - private static int VRefresh { - get { - if (vRefresh == 0) { - // get te hDC of the desktop to get the VREFRESH - IntPtr hDCDesktop = User32.GetWindowDC(User32.GetDesktopWindow()); - vRefresh = GDI32.GetDeviceCaps(hDCDesktop, DeviceCaps.VREFRESH); - User32.ReleaseDC(hDCDesktop); - } - return vRefresh; - } - } - - /// - /// Check if we need to optimize for RDP / Terminal Server sessions - /// - private static bool optimizeForTerminalServer { - get { - return conf.OptimizeForRDP || SystemInformation.TerminalServerSession; - } - } - - /// - /// Calculate the amount of frames that an animation takes - /// - /// - /// Number of frames, 1 if in Terminal Server Session - private static int calculateFrames(int milliseconds) { - // If we are in a Terminal Server Session we return 1 - if (optimizeForTerminalServer) { - return 1; - } - return milliseconds / VRefresh; - } - /// /// Property to access the selected capture rectangle /// @@ -153,7 +118,7 @@ namespace Greenshot.Forms { /// /// /// - public CaptureForm(ICapture capture, List windows) { + public CaptureForm(ICapture capture, List windows) : base() { if (currentForm != null) { LOG.Debug("Found currentForm, Closing already opened CaptureForm"); currentForm.Close(); @@ -162,9 +127,6 @@ namespace Greenshot.Forms { } currentForm = this; - // comment this out if the timer should not be used - timer = new Timer(); - // Using 32bppPArgb speeds up the drawing. //capturedImage = ImageHelper.Clone(capture.Image, PixelFormat.Format32bppPArgb); // comment the clone, uncomment the assignment and the original bitmap is used. @@ -185,16 +147,13 @@ namespace Greenshot.Forms { // InitializeComponent(); // Only double-buffer when we are not in a TerminalServerSession - this.DoubleBuffered = !optimizeForTerminalServer; + this.DoubleBuffered = !OptimizeForTerminalServer; this.Text = "Greenshot capture form"; // Make sure we never capture the captureform WindowDetails.RegisterIgnoreHandle(this.Handle); // Unregister at close this.FormClosing += delegate { - if (timer != null) { - timer.Stop(); - } // remove the buffer if it was created inside this form if (capturedImage != capture.Image) { capturedImage.Dispose(); @@ -208,7 +167,7 @@ namespace Greenshot.Forms { // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor if (captureMode == CaptureMode.Window) { - windowAnimator = new RectangleAnimator(new Rectangle(cursorPos, Size.Empty), captureRect, calculateFrames(700), EasingType.Quintic, EasingMode.EaseOut); + windowAnimator = new RectangleAnimator(new Rectangle(cursorPos, Size.Empty), captureRect, CalculateFrames(700), EasingType.Quintic, EasingMode.EaseOut); } // Set the zoomer animation @@ -221,12 +180,6 @@ namespace Greenshot.Forms { // Fix missing focus WindowDetails.ToForeground(this.Handle); this.TopMost = true; - - if (timer != null) { - timer.Interval = 1000/VRefresh; - timer.Tick += new EventHandler(timer_Tick); - timer.Start(); - } } /// @@ -235,10 +188,10 @@ namespace Greenshot.Forms { void InitializeZoomer(bool isOn) { if (isOn) { // Initialize the zoom with a invalid position - zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), calculateFrames(1000), EasingType.Quintic, EasingMode.EaseOut); + zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), CalculateFrames(1000), EasingType.Quintic, EasingMode.EaseOut); VerifyZoomAnimation(cursorPos, false); } else if (zoomAnimator != null) { - zoomAnimator.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), calculateFrames(1000)); + zoomAnimator.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), CalculateFrames(1000)); } } @@ -310,7 +263,7 @@ namespace Greenshot.Forms { // "Fade out" Zoom InitializeZoomer(false); // "Fade in" window - windowAnimator = new RectangleAnimator(new Rectangle(cursorPos, Size.Empty), captureRect, calculateFrames(700), EasingType.Quintic, EasingMode.EaseOut); + windowAnimator = new RectangleAnimator(new Rectangle(cursorPos, Size.Empty), captureRect, CalculateFrames(700), EasingType.Quintic, EasingMode.EaseOut); captureRect = Rectangle.Empty; Invalidate(); break; @@ -318,7 +271,7 @@ namespace Greenshot.Forms { // Set the region capture mode captureMode = CaptureMode.Region; // "Fade out" window - windowAnimator.ChangeDestination(new Rectangle(cursorPos, Size.Empty), calculateFrames(700)); + windowAnimator.ChangeDestination(new Rectangle(cursorPos, Size.Empty), CalculateFrames(700)); // Fade in zoom InitializeZoomer(conf.ZoomerEnabled); captureRect = Rectangle.Empty; @@ -412,20 +365,6 @@ namespace Greenshot.Forms { // Make sure the mouse coordinates are fixed, when pressing shift mouseMovePos = FixMouseCoordinates(WindowCapture.GetCursorLocation()); mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); - // If the timer is used, the timer_Tick does the following. - // If the timer is not used, we need to call the update ourselves - if (timer == null) { - updateFrame(); - } - } - - /// - /// The tick handler of the capture form, this initiates the frame drawing. - /// - /// - /// - void timer_Tick(object sender, EventArgs e) { - updateFrame(); } /// @@ -443,7 +382,7 @@ namespace Greenshot.Forms { /// /// update the frame, this only invalidates /// - void updateFrame() { + protected override void Animate() { Point lastPos = cursorPos.Clone(); cursorPos = mouseMovePos.Clone(); @@ -526,7 +465,7 @@ namespace Greenshot.Forms { invalidateRectangle = new Rectangle(x1,y1, x2-x1, y2-y1); Invalidate(invalidateRectangle); } else if (captureMode != CaptureMode.Window) { - if (!optimizeForTerminalServer) { + if (!OptimizeForTerminalServer) { Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); if (verticalMove) { @@ -549,7 +488,7 @@ namespace Greenshot.Forms { } else { if (selectedCaptureWindow != null && !selectedCaptureWindow.Equals(lastWindow)) { // Window changes, make new animation from current to target - windowAnimator.ChangeDestination(captureRect, calculateFrames(700)); + windowAnimator.ChangeDestination(captureRect, CalculateFrames(700)); } } // always animate the Window area through to the last frame, so we see the fade-in/out untill the end @@ -657,11 +596,9 @@ namespace Greenshot.Forms { using (GraphicsPath path = new GraphicsPath()) { path.AddEllipse(destinationRectangle); - using (Region clipRegion = new Region(path)) { - graphics.Clip = clipRegion; - graphics.FillRectangle(backgroundBrush, destinationRectangle); - graphics.DrawImage(capturedImage, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); - } + graphics.SetClip(path); + graphics.FillRectangle(backgroundBrush, destinationRectangle); + graphics.DrawImage(capturedImage, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); } // Draw the circle around the zoomer @@ -842,7 +779,7 @@ namespace Greenshot.Forms { } } } else { - if (!optimizeForTerminalServer) { + if (!OptimizeForTerminalServer) { using (Pen pen = new Pen(Color.LightSeaGreen)) { pen.DashStyle = DashStyle.Dot; Rectangle screenBounds = capture.ScreenBounds; diff --git a/GreenshotPlugin/Controls/AnimatingForm.cs b/GreenshotPlugin/Controls/AnimatingForm.cs new file mode 100644 index 000000000..9f9efe1c3 --- /dev/null +++ b/GreenshotPlugin/Controls/AnimatingForm.cs @@ -0,0 +1,107 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on 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 GreenshotPlugin.Core; +using GreenshotPlugin.UnmanagedHelpers; +using Greenshot.IniFile; + +namespace GreenshotPlugin.Controls { + /// + /// Extend this Form to have the possibility for animations on your form + /// + public abstract class AnimatingForm : Form { + protected static CoreConfiguration coreConfiguration = IniConfig.GetIniSection(); + private int vRefresh = 0; + private Timer timer = null; + + /// + /// Vertical Refresh Rate + /// + protected int VRefresh { + get { + if (vRefresh == 0) { + // get te hDC of the desktop to get the VREFRESH + IntPtr hDCDesktop = User32.GetWindowDC(User32.GetDesktopWindow()); + vRefresh = GDI32.GetDeviceCaps(hDCDesktop, DeviceCaps.VREFRESH); + User32.ReleaseDC(hDCDesktop); + } + return vRefresh; + } + } + + /// + /// Check if we need to optimize for RDP / Terminal Server sessions + /// + protected bool OptimizeForTerminalServer { + get { + return coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession; + } + } + + /// + /// Calculate the amount of frames that an animation takes + /// + /// + /// Number of frames, 1 if in Terminal Server Session + protected int CalculateFrames(int milliseconds) { + // If we are in a Terminal Server Session we return 1 + if (OptimizeForTerminalServer) { + return 1; + } + return milliseconds / VRefresh; + } + + /// + /// Initialize the animation + /// + protected AnimatingForm() { + timer = new Timer(); + timer.Interval = 1000 / VRefresh; + timer.Tick += new EventHandler(timer_Tick); + + this.Load += delegate { + timer.Start(); + }; + + // Unregister at close + this.FormClosing += delegate { + if (timer != null) { + timer.Stop(); + } + }; + } + + /// + /// The tick handler initiates the animation. + /// + /// + /// + void timer_Tick(object sender, EventArgs e) { + Animate(); + } + + /// + /// This method will be called every frame, so implement your animation/redraw logic here. + /// + protected abstract void Animate(); + } +} diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 5b8e82419..8595be9fe 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -28,6 +28,9 @@ + + Form + @@ -201,32 +204,4 @@ rmdir /S /Q "$(SolutionDir)bin\$(Configuration)\Plugins" "$(SolutionDir)tools\TortoiseSVN\SubWCRev.exe" "$(ProjectDir)." "$(ProjectDir)Properties\AssemblyInfo.cs.template" "$(ProjectDir)Properties\AssemblyInfo.cs" - - False - Off - 4194304 - x86 - 4096 - - - False - Off - 4194304 - AnyCPU - 4096 - - - True - False - None - false - TRACE - - - False - True - Full - true - DEBUG;TRACE - \ No newline at end of file