Quasar/Server/Controls/RapidPictureBox.cs

191 lines
5.3 KiB
C#
Raw Normal View History

2015-07-28 14:48:39 -07:00
using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using xServer.Core.Utilities;
namespace xServer.Controls
{
public interface IRapidPictureBox
{
bool Running { get; set; }
Image GetImageSafe { get; set; }
void Start();
void Stop();
void UpdateImage(Bitmap bmp, bool cloneBitmap = false);
}
/// <summary>
/// Custom PictureBox Control designed for rapidly-changing images.
/// </summary>
public class RapidPictureBox : PictureBox, IRapidPictureBox
{
/// <summary>
/// True if the PictureBox is currently streaming images, else False.
/// </summary>
public bool Running { get; set; }
/// <summary>
/// Returns the width of the original screen.
/// </summary>
public int ScreenWidth { get; private set; }
/// <summary>
/// Returns the height of the original screen.
/// </summary>
public int ScreenHeight { get; private set; }
/// <summary>
/// Provides thread-safe access to the Image of this Picturebox.
/// </summary>
public Image GetImageSafe
{
get
{
return Image;
}
set
{
lock (_imageLock)
{
Image = value;
}
}
}
/// <summary>
/// The lock object for the Picturebox's image.
/// </summary>
private readonly object _imageLock = new object();
/// <summary>
/// The Stopwatch for internal FPS measuring.
/// </summary>
private Stopwatch _sWatch;
/// <summary>
/// The internal class for FPS measuring.
/// </summary>
private FrameCounter _frameCounter;
/// <summary>
/// Subscribes an Eventhandler to the FrameUpdated event.
/// </summary>
/// <param name="e">The Eventhandler to set.</param>
public void SetFrameUpdatedEvent(FrameUpdatedEventHandler e)
{
_frameCounter.FrameUpdated += e;
}
/// <summary>
/// Unsubscribes an Eventhandler from the FrameUpdated event.
/// </summary>
/// <param name="e">The Eventhandler to remove.</param>
public void UnsetFrameUpdatedEvent(FrameUpdatedEventHandler e)
{
_frameCounter.FrameUpdated -= e;
}
/// <summary>
/// Starts the internal FPS measuring.
/// </summary>
public void Start()
{
_sWatch = Stopwatch.StartNew();
Running = true;
}
/// <summary>
/// Stops the internal FPS measuring.
/// </summary>
public void Stop()
{
if (_sWatch != null)
_sWatch.Stop();
Running = false;
}
/// <summary>
/// Updates the Image of this Picturebox.
/// </summary>
/// <param name="bmp">The new bitmap to use.</param>
/// <param name="cloneBitmap">If True the bitmap will be cloned, else it uses the original bitmap.</param>
public void UpdateImage(Bitmap bmp, bool cloneBitmap)
2015-07-28 14:48:39 -07:00
{
try
{
CountFps();
if ((ScreenWidth != bmp.Width) && (ScreenHeight != bmp.Height))
UpdateScreenSize(bmp.Width, bmp.Height);
lock (_imageLock)
{
2015-07-28 15:12:31 -07:00
// get old image to dispose it correctly
var oldImage = GetImageSafe;
SuspendLayout();
2015-07-28 14:48:39 -07:00
GetImageSafe = cloneBitmap ? new Bitmap(bmp, Width, Height) /*resize bitmap*/ : bmp;
2015-07-28 15:12:31 -07:00
ResumeLayout();
if (oldImage != null)
oldImage.Dispose();
2015-07-28 14:48:39 -07:00
}
}
catch (InvalidOperationException)
{
}
2015-07-28 15:12:31 -07:00
catch (Exception)
2015-07-28 14:48:39 -07:00
{
}
}
/// <summary>
/// Constructor, sets Picturebox double-buffered and initializes the Framecounter.
/// </summary>
public RapidPictureBox()
{
this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
_frameCounter = new FrameCounter();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
protected override void OnPaint(PaintEventArgs pe)
{
lock (_imageLock)
{
if (GetImageSafe != null)
{
pe.Graphics.DrawImage(GetImageSafe, Location);
}
}
}
private void UpdateScreenSize(int newWidth, int newHeight)
{
ScreenWidth = newWidth;
ScreenHeight = newHeight;
}
private void CountFps()
{
var deltaTime = (float)_sWatch.Elapsed.TotalSeconds;
_sWatch = Stopwatch.StartNew();
_frameCounter.Update(deltaTime);
}
}
}