using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Vanara.PInvoke;
using static Vanara.PInvoke.Gdi32;
using static Vanara.PInvoke.UxTheme;
namespace Vanara.Drawing
{
/// Buffered painting helper class.
public static class BufferedPaint
{
private static readonly Dictionary> paintAnimationInstances = new Dictionary>();
/// A method delegate that retrieves a duration, in milliseconds, to use as the time over which buffered painting occurs.
/// The type of the state that is used to determine the transition duration.
/// The old state value.
/// The new state value.
/// A duration, in milliseconds, to use as the time over which buffered painting occurs.
public delegate int GetDuration(TState oldState, TState newState);
/// A method delegate to paint a stateful image.
/// The type of the state that is used to determine the image to paint.
/// The type of the parameter that is passed into this method.
/// The graphics instance on which to paint the image.
/// The bounds within which to paint the image.
/// The current state to paint.
/// The custom data passed into this method.
public delegate void PaintAction(Graphics graphics, Rectangle bounds, TState currentState, TParam data);
/// Performs a buffered paint operation.
/// The type of the state that is used to determine the image to paint.
/// The type of the parameter that is passed into this method.
/// The target DC on which the buffer is painted.
/// Specifies the area of the target DC in which to draw.
/// A method delegate that performs the painting of the control at the provided state.
/// The current state to use to start drawing the animation.
/// User-defined data to pass to the callback.
public static void Paint(Graphics graphics, Rectangle bounds, PaintAction paintAction, TState currentState, TParam data)
{
using (var g = new SafeHDC(graphics))
using (var bp = new BufferedPainter(g, bounds))
paintAction(bp.Graphics, bounds, currentState, data);
}
/// Performs a buffered animation operation. The animation consists of a cross-fade between the contents of two buffers over a specified period of time.
/// The type of the state that is used to determine the image to paint.
/// The target DC on which the buffer is animated.
/// The window in which the animations play.
/// Specifies the area of the target DC in which to draw.
/// A method delegate that performs the painting of the control at a given state.
/// The current state to use to start drawing the animation.
/// The final state to use to finish drawing the animation.
/// A method delegate that gets the duration of the animation, in milliseconds.
public static void PaintAnimation(Graphics graphics, IWin32Window ctrl, Rectangle bounds, PaintAction paintAction,
TState currentState, TState newState, GetDuration getDuration)
=> PaintAnimation(graphics, ctrl, bounds, paintAction, currentState, newState, getDuration, 0);
/// Performs a buffered animation operation. The animation consists of a cross-fade between the contents of two buffers over a specified period of time.
/// The type of the state that is used to determine the image to paint.
/// The type of the parameter that is passed into this method.
/// The target DC on which the buffer is animated.
/// The window in which the animations play.
/// Specifies the area of the target DC in which to draw.
/// A method delegate that performs the painting of the control at a given state.
/// The current state to use to start drawing the animation.
/// The final state to use to finish drawing the animation.
/// A method delegate that gets the duration of the animation, in milliseconds.
/// User-defined data to pass to the callback.
public static void PaintAnimation(Graphics graphics, IWin32Window ctrl, Rectangle bounds,
PaintAction paintAction, TState currentState, TState newState, GetDuration getDuration, TParam data)
{
try
{
if (System.Environment.OSVersion.Version.Major >= 6)
{
// If this handle is running with a different state, stop the animations
if (paintAnimationInstances.TryGetValue(ctrl.Handle, out var val))
{
if (!Equals(val.Item1, currentState) || !Equals(val.Item2, newState))
{
BufferedPaintStopAllAnimations(ctrl.Handle);
System.Diagnostics.Debug.WriteLine("BufferedPaintStop.");
paintAnimationInstances[ctrl.Handle] = new Tuple