A round of code cleanup on InputRoll and GDI Renderer
This commit is contained in:
parent
28b26fadcc
commit
b5638798b2
|
@ -1,158 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk.CustomControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper for GDI text rendering functions<br/>
|
||||
/// This class is not thread-safe as GDI function should be called from the UI thread.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Wrapper for GDI rendering functions
|
||||
/// This class is not thread-safe as GDI functions should be called from the UI thread
|
||||
/// </summary>
|
||||
public sealed class GDIRenderer : IDisposable
|
||||
{
|
||||
#region Fields and Consts
|
||||
|
||||
/// <summary>
|
||||
/// used for <see cref="MeasureString(string,System.Drawing.Font,float,out int,out int)"/> calculation.
|
||||
/// </summary>
|
||||
private static readonly int[] _charFit = new int[1];
|
||||
|
||||
/// <summary>
|
||||
/// used for <see cref="MeasureString(string,System.Drawing.Font,float,out int,out int)"/> calculation.
|
||||
/// </summary>
|
||||
private static readonly int[] _charFitWidth = new int[1000];
|
||||
|
||||
/// <summary>
|
||||
/// cache of all the font used not to create same font again and again
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, Dictionary<float, Dictionary<FontStyle, IntPtr>>> _fontsCache = new Dictionary<string, Dictionary<float, Dictionary<FontStyle, IntPtr>>>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// The wrapped WinForms graphics object
|
||||
/// </summary>
|
||||
private Graphics _g;
|
||||
|
||||
/// <summary>
|
||||
/// the initialized HDC used
|
||||
/// </summary>
|
||||
private IntPtr _hdc;
|
||||
|
||||
#endregion
|
||||
|
||||
public class GdiGraphicsLock : IDisposable
|
||||
{
|
||||
public GdiGraphicsLock(GDIRenderer gdi)
|
||||
{
|
||||
this.gdi = gdi;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
gdi._g.ReleaseHdc(gdi._hdc);
|
||||
gdi._hdc = IntPtr.Zero;
|
||||
gdi._g = null;
|
||||
}
|
||||
|
||||
GDIRenderer gdi;
|
||||
}
|
||||
|
||||
public GdiGraphicsLock LockGraphics(Graphics g)
|
||||
{
|
||||
_g = g;
|
||||
_hdc = g.GetHdc();
|
||||
SetBkMode(_hdc, (int)BkModes.TRANSPARENT);
|
||||
return new GdiGraphicsLock(this);
|
||||
}
|
||||
/// <summary>
|
||||
/// used for <see cref="MeasureString(string, System.Drawing.Font, float, out int, out int)"/> calculation.
|
||||
/// </summary>
|
||||
private static readonly int[] CharFit = new int[1];
|
||||
|
||||
/// <summary>
|
||||
/// Init.
|
||||
/// used for <see cref="MeasureString(string, System.Drawing.Font,float, out int, out int)"/> calculation
|
||||
/// </summary>
|
||||
private static readonly int[] CharFitWidth = new int[1000];
|
||||
|
||||
/// <summary>
|
||||
/// Cache of all the fonts used, rather than create them again and again
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, Dictionary<float, Dictionary<FontStyle, IntPtr>>> FontsCache = new Dictionary<string, Dictionary<float, Dictionary<FontStyle, IntPtr>>>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Cache of all the brushes used, rather than create them again and again
|
||||
/// </summary>
|
||||
private readonly Dictionary<Color, IntPtr> BrushCache = new Dictionary<Color, IntPtr>();
|
||||
|
||||
private Graphics _g;
|
||||
private IntPtr _hdc;
|
||||
private IntPtr _currentBrush = IntPtr.Zero;
|
||||
|
||||
#region Construct and Destroy
|
||||
|
||||
public GDIRenderer()
|
||||
{
|
||||
SetBkMode(_hdc, (int)BkModes.OPAQUE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Measure the width and height of string <paramref name="str"/> when drawn on device context HDC
|
||||
/// using the given font <paramref name="font"/>.
|
||||
/// </summary>
|
||||
/// <param name="str">the string to measure</param>
|
||||
/// <param name="font">the font to measure string with</param>
|
||||
/// <returns>the size of the string</returns>
|
||||
public Size MeasureString(string str, Font font)
|
||||
{
|
||||
SetFont(font);
|
||||
|
||||
var size = new Size();
|
||||
GetTextExtentPoint32(_hdc, str, str.Length, ref size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Measure the width and height of string <paramref name="str"/> when drawn on device context HDC
|
||||
/// using the given font <paramref name="font"/>.<br/>
|
||||
/// Restrict the width of the string and get the number of characters able to fit in the restriction and
|
||||
/// the width those characters take.
|
||||
/// </summary>
|
||||
/// <param name="str">the string to measure</param>
|
||||
/// <param name="font">the font to measure string with</param>
|
||||
/// <param name="maxWidth">the max width to render the string in</param>
|
||||
/// <param name="charFit">the number of characters that will fit under <see cref="maxWidth"/> restriction</param>
|
||||
/// <param name="charFitWidth"></param>
|
||||
/// <returns>the size of the string</returns>
|
||||
public Size MeasureString(string str, Font font, float maxWidth, out int charFit, out int charFitWidth)
|
||||
{
|
||||
SetFont(font);
|
||||
|
||||
var size = new Size();
|
||||
GetTextExtentExPoint(_hdc, str, str.Length, (int)Math.Round(maxWidth), _charFit, _charFitWidth, ref size);
|
||||
charFit = _charFit[0];
|
||||
charFitWidth = charFit > 0 ? _charFitWidth[charFit - 1] : 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the given string using the given font and foreground color at given location.
|
||||
/// </summary>
|
||||
/// <param name="str">the string to draw</param>
|
||||
/// <param name="font">the font to use to draw the string</param>
|
||||
/// <param name="color">the text color to set</param>
|
||||
/// <param name="point">the location to start string draw (top-left)</param>
|
||||
public void DrawString(String str, Point point)
|
||||
{
|
||||
TextOut(_hdc, point.X, point.Y, str, str.Length);
|
||||
}
|
||||
|
||||
public void PrepDrawString(Font font, Color color)
|
||||
{
|
||||
SetFont(font);
|
||||
SetTextColor(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the given string using the given font and foreground color at given location.<br/>
|
||||
/// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15].
|
||||
/// </summary>
|
||||
/// <param name="str">the string to draw</param>
|
||||
/// <param name="font">the font to use to draw the string</param>
|
||||
/// <param name="color">the text color to set</param>
|
||||
/// <param name="rect">the rectangle in which the text is to be formatted</param>
|
||||
/// <param name="flags">The method of formatting the text</param>
|
||||
public void DrawString(String str, Font font, Color color, Rectangle rect, TextFormatFlags flags)
|
||||
{
|
||||
SetFont(font);
|
||||
SetTextColor(color);
|
||||
|
||||
var rect2 = new Rect(rect);
|
||||
DrawText(_hdc, str, str.Length, ref rect2, (uint)flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release current HDC to be able to use <see cref="Graphics"/> methods.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var brush in BrushCache)
|
||||
|
@ -167,54 +56,81 @@ namespace BizHawk.Client.EmuHawk.CustomControls
|
|||
System.Diagnostics.Debug.Assert(_g == null, "Disposed a GDIRenderer while it held a Graphics");
|
||||
}
|
||||
|
||||
#region Private methods
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Set a resource (e.g. a font) for the specified device context.
|
||||
/// </summary>
|
||||
private void SetFont(Font font)
|
||||
#region Api
|
||||
|
||||
/// <summary>
|
||||
/// Required to use before calling drawing methods
|
||||
/// </summary>
|
||||
public GdiGraphicsLock LockGraphics(Graphics g)
|
||||
{
|
||||
SelectObject(_hdc, GetCachedHFont(font));
|
||||
_g = g;
|
||||
_hdc = g.GetHdc();
|
||||
SetBkMode(_hdc, (int)BkModes.TRANSPARENT);
|
||||
return new GdiGraphicsLock(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Measure the width and height of string <paramref name="str"/> when drawn on device context HDC
|
||||
/// using the given font <paramref name="font"/>
|
||||
/// </summary>
|
||||
public Size MeasureString(string str, Font font)
|
||||
{
|
||||
SetFont(font);
|
||||
|
||||
var size = new Size();
|
||||
GetTextExtentPoint32(_hdc, str, str.Length, ref size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get cached unmanaged font handle for given font.<br/>
|
||||
/// </summary>
|
||||
/// <param name="font">the font to get unmanaged font handle for</param>
|
||||
/// <returns>handle to unmanaged font</returns>
|
||||
private static IntPtr GetCachedHFont(Font font)
|
||||
/// Measure the width and height of string <paramref name="str"/> when drawn on device context HDC
|
||||
/// using the given font <paramref name="font"/>
|
||||
/// Restrict the width of the string and get the number of characters able to fit in the restriction and
|
||||
/// the width those characters take
|
||||
/// </summary>
|
||||
/// <param name="maxWidth">the max width to render the string in</param>
|
||||
/// <param name="charFit">the number of characters that will fit under <see cref="maxWidth"/> restriction</param>
|
||||
/// <param name="charFitWidth"></param>
|
||||
public Size MeasureString(string str, Font font, float maxWidth, out int charFit, out int charFitWidth)
|
||||
{
|
||||
IntPtr hfont = IntPtr.Zero;
|
||||
Dictionary<float, Dictionary<FontStyle, IntPtr>> dic1;
|
||||
if (_fontsCache.TryGetValue(font.Name, out dic1))
|
||||
{
|
||||
Dictionary<FontStyle, IntPtr> dic2;
|
||||
if (dic1.TryGetValue(font.Size, out dic2))
|
||||
{
|
||||
dic2.TryGetValue(font.Style, out hfont);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic1[font.Size] = new Dictionary<FontStyle, IntPtr>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_fontsCache[font.Name] = new Dictionary<float, Dictionary<FontStyle, IntPtr>>();
|
||||
_fontsCache[font.Name][font.Size] = new Dictionary<FontStyle, IntPtr>();
|
||||
}
|
||||
SetFont(font);
|
||||
|
||||
if (hfont == IntPtr.Zero)
|
||||
{
|
||||
_fontsCache[font.Name][font.Size][font.Style] = hfont = font.ToHfont();
|
||||
}
|
||||
|
||||
return hfont;
|
||||
var size = new Size();
|
||||
GetTextExtentExPoint(_hdc, str, str.Length, (int)Math.Round(maxWidth), CharFit, CharFitWidth, ref size);
|
||||
charFit = CharFit[0];
|
||||
charFitWidth = charFit > 0 ? CharFitWidth[charFit - 1] : 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the text color of the device context.
|
||||
/// </summary>
|
||||
public void DrawString(string str, Point point)
|
||||
{
|
||||
TextOut(_hdc, point.X, point.Y, str, str.Length);
|
||||
}
|
||||
|
||||
public void PrepDrawString(Font font, Color color)
|
||||
{
|
||||
SetFont(font);
|
||||
SetTextColor(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the given string using the given font and foreground color at given location
|
||||
/// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15]
|
||||
/// </summary>
|
||||
public void DrawString(string str, Font font, Color color, Rectangle rect, TextFormatFlags flags)
|
||||
{
|
||||
SetFont(font);
|
||||
SetTextColor(color);
|
||||
|
||||
var rect2 = new Rect(rect);
|
||||
DrawText(_hdc, str, str.Length, ref rect2, (uint)flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the text color of the device context
|
||||
/// </summary>
|
||||
public void SetTextColor(Color color)
|
||||
{
|
||||
int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
|
||||
|
@ -232,7 +148,6 @@ namespace BizHawk.Client.EmuHawk.CustomControls
|
|||
Rectangle(_hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
|
||||
}
|
||||
|
||||
// TODO: use the "current brush" instead of grabbing a new one
|
||||
public void SetBrush(Color color)
|
||||
{
|
||||
if (BrushCache.ContainsKey(color))
|
||||
|
@ -248,12 +163,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls
|
|||
}
|
||||
}
|
||||
|
||||
//private IntPtr _brush = IntPtr.Zero;
|
||||
|
||||
Dictionary<Color, IntPtr> BrushCache = new Dictionary<Color, IntPtr>();
|
||||
private IntPtr _currentBrush = IntPtr.Zero;
|
||||
|
||||
public void FillRectangle(int x,int y, int w, int h)
|
||||
public void FillRectangle(int x, int y, int w, int h)
|
||||
{
|
||||
var r = new GDIRect(new Rectangle(x, y, x + w, y + h));
|
||||
FillRect(_hdc, ref r, _currentBrush);
|
||||
|
@ -277,50 +187,46 @@ namespace BizHawk.Client.EmuHawk.CustomControls
|
|||
LineTo(_hdc, x2, y2);
|
||||
}
|
||||
|
||||
// ReSharper disable NotAccessedField.Local
|
||||
private struct Rect
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Set a resource (e.g. a font) for the specified device context.
|
||||
/// </summary>
|
||||
private void SetFont(Font font)
|
||||
{
|
||||
private int _left;
|
||||
private int _top;
|
||||
private int _right;
|
||||
private int _bottom;
|
||||
|
||||
public Rect(Rectangle r)
|
||||
{
|
||||
_left = r.Left;
|
||||
_top = r.Top;
|
||||
_bottom = r.Bottom;
|
||||
_right = r.Right;
|
||||
}
|
||||
}
|
||||
// ReSharper restore NotAccessedField.Local
|
||||
|
||||
private struct GDIRect
|
||||
{
|
||||
private int left;
|
||||
private int top;
|
||||
private int right;
|
||||
private int bottom;
|
||||
|
||||
public GDIRect(Rectangle r)
|
||||
{
|
||||
left = r.Left;
|
||||
top = r.Top;
|
||||
bottom = r.Bottom;
|
||||
right = r.Right;
|
||||
}
|
||||
SelectObject(_hdc, GetCachedHFont(font));
|
||||
}
|
||||
|
||||
private struct GDIPoint
|
||||
private static IntPtr GetCachedHFont(Font font)
|
||||
{
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
private GDIPoint(int x, int y)
|
||||
var hfont = IntPtr.Zero;
|
||||
Dictionary<float, Dictionary<FontStyle, IntPtr>> dic1;
|
||||
if (FontsCache.TryGetValue(font.Name, out dic1))
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
Dictionary<FontStyle, IntPtr> dic2;
|
||||
if (dic1.TryGetValue(font.Size, out dic2))
|
||||
{
|
||||
dic2.TryGetValue(font.Style, out hfont);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic1[font.Size] = new Dictionary<FontStyle, IntPtr>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FontsCache[font.Name] = new Dictionary<float, Dictionary<FontStyle, IntPtr>>();
|
||||
FontsCache[font.Name][font.Size] = new Dictionary<FontStyle, IntPtr>();
|
||||
}
|
||||
|
||||
if (hfont == IntPtr.Zero)
|
||||
{
|
||||
FontsCache[font.Name][font.Size][font.Style] = hfont = font.ToHfont();
|
||||
}
|
||||
|
||||
return hfont;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -343,7 +249,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls
|
|||
private static extern int Rectangle(IntPtr hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int FillRect(IntPtr hDC, [In] ref GDIRect lprc, IntPtr hbr);
|
||||
private static extern int FillRect(IntPtr hdc, [In] ref GDIRect lprc, IntPtr hbr);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern int SetBkMode(IntPtr hdc, int mode);
|
||||
|
@ -394,71 +300,136 @@ namespace BizHawk.Client.EmuHawk.CustomControls
|
|||
private static extern IntPtr SetDCPenColor(IntPtr hdc, int crColor);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15]
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum TextFormatFlags : uint
|
||||
{
|
||||
Default = 0x00000000,
|
||||
Center = 0x00000001,
|
||||
Right = 0x00000002,
|
||||
VCenter = 0x00000004,
|
||||
Bottom = 0x00000008,
|
||||
WordBreak = 0x00000010,
|
||||
SingleLine = 0x00000020,
|
||||
ExpandTabs = 0x00000040,
|
||||
TabStop = 0x00000080,
|
||||
NoClip = 0x00000100,
|
||||
ExternalLeading = 0x00000200,
|
||||
CalcRect = 0x00000400,
|
||||
NoPrefix = 0x00000800,
|
||||
Internal = 0x00001000,
|
||||
EditControl = 0x00002000,
|
||||
PathEllipsis = 0x00004000,
|
||||
EndEllipsis = 0x00008000,
|
||||
ModifyString = 0x00010000,
|
||||
RtlReading = 0x00020000,
|
||||
WordEllipsis = 0x00040000,
|
||||
NoFullWidthCharBreak = 0x00080000,
|
||||
HidePrefix = 0x00100000,
|
||||
ProfixOnly = 0x00200000,
|
||||
}
|
||||
#region Classes, Structs, and Enums
|
||||
|
||||
[Flags]
|
||||
public enum PenStyles
|
||||
{
|
||||
PS_SOLID = 0x00000000
|
||||
// TODO
|
||||
}
|
||||
public class GdiGraphicsLock : IDisposable
|
||||
{
|
||||
private readonly GDIRenderer Gdi;
|
||||
|
||||
public enum PaintObjects
|
||||
{
|
||||
WHITE_BRUSH = 0,
|
||||
LTGRAY_BRUSH = 1,
|
||||
GRAY_BRUSH = 2,
|
||||
DKGRAY_BRUSH = 3,
|
||||
BLACK_BRUSH = 4,
|
||||
NULL_BRUSH = 5,
|
||||
WHITE_PEN = 6,
|
||||
BLACK_PEN = 7,
|
||||
NULL_PEN = 8,
|
||||
OEM_FIXED_FONT = 10,
|
||||
ANSI_FIXED_FONT = 11,
|
||||
ANSI_VAR_FONT = 12,
|
||||
SYSTEM_FONT = 13,
|
||||
DEVICE_DEFAULT_FONT = 14,
|
||||
DEFAULT_PALETTE = 15,
|
||||
SYSTEM_FIXED_FONT = 16,
|
||||
DC_BRUSH = 18,
|
||||
DC_PEN = 19,
|
||||
}
|
||||
public GdiGraphicsLock(GDIRenderer gdi)
|
||||
{
|
||||
this.Gdi = gdi;
|
||||
}
|
||||
|
||||
public enum BkModes
|
||||
{
|
||||
TRANSPARENT = 1,
|
||||
OPAQUE = 2
|
||||
public void Dispose()
|
||||
{
|
||||
Gdi._g.ReleaseHdc(Gdi._hdc);
|
||||
Gdi._hdc = IntPtr.Zero;
|
||||
Gdi._g = null;
|
||||
}
|
||||
}
|
||||
|
||||
private struct Rect
|
||||
{
|
||||
private int _left;
|
||||
private int _top;
|
||||
private int _right;
|
||||
private int _bottom;
|
||||
|
||||
public Rect(Rectangle r)
|
||||
{
|
||||
_left = r.Left;
|
||||
_top = r.Top;
|
||||
_bottom = r.Bottom;
|
||||
_right = r.Right;
|
||||
}
|
||||
}
|
||||
|
||||
private struct GDIRect
|
||||
{
|
||||
private int left;
|
||||
private int top;
|
||||
private int right;
|
||||
private int bottom;
|
||||
|
||||
public GDIRect(Rectangle r)
|
||||
{
|
||||
left = r.Left;
|
||||
top = r.Top;
|
||||
bottom = r.Bottom;
|
||||
right = r.Right;
|
||||
}
|
||||
}
|
||||
|
||||
private struct GDIPoint
|
||||
{
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
private GDIPoint(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15]
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum TextFormatFlags : uint
|
||||
{
|
||||
Default = 0x00000000,
|
||||
Center = 0x00000001,
|
||||
Right = 0x00000002,
|
||||
VCenter = 0x00000004,
|
||||
Bottom = 0x00000008,
|
||||
WordBreak = 0x00000010,
|
||||
SingleLine = 0x00000020,
|
||||
ExpandTabs = 0x00000040,
|
||||
TabStop = 0x00000080,
|
||||
NoClip = 0x00000100,
|
||||
ExternalLeading = 0x00000200,
|
||||
CalcRect = 0x00000400,
|
||||
NoPrefix = 0x00000800,
|
||||
Internal = 0x00001000,
|
||||
EditControl = 0x00002000,
|
||||
PathEllipsis = 0x00004000,
|
||||
EndEllipsis = 0x00008000,
|
||||
ModifyString = 0x00010000,
|
||||
RtlReading = 0x00020000,
|
||||
WordEllipsis = 0x00040000,
|
||||
NoFullWidthCharBreak = 0x00080000,
|
||||
HidePrefix = 0x00100000,
|
||||
ProfixOnly = 0x00200000,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PenStyles
|
||||
{
|
||||
PS_SOLID = 0x00000000
|
||||
// TODO
|
||||
}
|
||||
|
||||
public enum PaintObjects
|
||||
{
|
||||
WHITE_BRUSH = 0,
|
||||
LTGRAY_BRUSH = 1,
|
||||
GRAY_BRUSH = 2,
|
||||
DKGRAY_BRUSH = 3,
|
||||
BLACK_BRUSH = 4,
|
||||
NULL_BRUSH = 5,
|
||||
WHITE_PEN = 6,
|
||||
BLACK_PEN = 7,
|
||||
NULL_PEN = 8,
|
||||
OEM_FIXED_FONT = 10,
|
||||
ANSI_FIXED_FONT = 11,
|
||||
ANSI_VAR_FONT = 12,
|
||||
SYSTEM_FONT = 13,
|
||||
DEVICE_DEFAULT_FONT = 14,
|
||||
DEFAULT_PALETTE = 15,
|
||||
SYSTEM_FIXED_FONT = 16,
|
||||
DC_BRUSH = 18,
|
||||
DC_PEN = 19,
|
||||
}
|
||||
|
||||
public enum BkModes
|
||||
{
|
||||
TRANSPARENT = 1,
|
||||
OPAQUE = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.EmuHawk.CustomControls;
|
||||
|
@ -22,21 +21,21 @@ namespace BizHawk.Client.EmuHawk
|
|||
public InputRoll()
|
||||
{
|
||||
CellPadding = 3;
|
||||
//SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
CurrentCell = null;
|
||||
Font = new Font("Courier New", 8); // Only support fixed width
|
||||
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
|
||||
SetStyle(ControlStyles.Opaque, true);
|
||||
this.Font = new Font("Courier New", 8); // Only support fixed width
|
||||
//BackColor = Color.Transparent;
|
||||
|
||||
Gdi = new GDIRenderer();
|
||||
|
||||
using (var g = CreateGraphics())
|
||||
using(var LCK = Gdi.LockGraphics(g))
|
||||
_charSize = Gdi.MeasureString("A", this.Font);
|
||||
|
||||
CurrentCell = null;
|
||||
using (var LCK = Gdi.LockGraphics(g))
|
||||
{
|
||||
_charSize = Gdi.MeasureString("A", this.Font);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
@ -51,6 +50,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// Gets or sets the amount of padding on the text inside a cell
|
||||
/// </summary>
|
||||
[DefaultValue(3)]
|
||||
[Category("Behavior")]
|
||||
public int CellPadding { get; set; }
|
||||
|
||||
// TODO: remove this, it is put here for more convenient replacing of a virtuallistview in tools with the need to refactor code
|
||||
|
@ -84,34 +84,36 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the background color for a Listview cell (item and subitem).
|
||||
/// </summary>
|
||||
/// <param name="index">Listview item (row).</param>
|
||||
/// <param name="column">Listview subitem (column).</param>
|
||||
/// <param name="color">Background color to use</param>
|
||||
public delegate void QueryItemBkColorHandler(int index, int column, ref Color color);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the text for a Listview cell (item and subitem).
|
||||
/// </summary>
|
||||
/// <param name="index">Listview item (row).</param>
|
||||
/// <param name="column">Listview subitem (column).</param>
|
||||
/// <param name="text">Text to display.</param>
|
||||
public delegate void QueryItemTextHandler(int index, int column, out string text);
|
||||
|
||||
/// <summary>
|
||||
/// Fire the QueryItemBkColor event which requests the background color for the passed Listview cell
|
||||
/// </summary>
|
||||
[Category("Virtual")] // TODO: can I make these up?
|
||||
public event QueryItemBkColorHandler QueryItemBkColor;
|
||||
|
||||
/// <summary>
|
||||
/// Fire the QueryItemText event which requests the text for the passed Listview cell.
|
||||
/// </summary>
|
||||
[Category("Virtual")]
|
||||
public event QueryItemTextHandler QueryItemText;
|
||||
|
||||
/// <summary>
|
||||
/// Fire the QueryItemBkColor event which requests the background color for the passed Listview cell
|
||||
/// </summary>
|
||||
[Category("Virtual")]
|
||||
public event QueryItemBkColorHandler QueryItemBkColor;
|
||||
|
||||
/// <summary>
|
||||
/// Fires when the mouse moves from one cell to another (including column header cells)
|
||||
/// </summary>
|
||||
[Category("Mouse")]
|
||||
public event CellChangeEventHandler PointedCellChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the text for a cell
|
||||
/// </summary>
|
||||
public delegate void QueryItemTextHandler(int index, int column, out string text);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the background color for a cell
|
||||
/// </summary>
|
||||
public delegate void QueryItemBkColorHandler(int index, int column, ref Color color);
|
||||
|
||||
public delegate void CellChangeEventHandler(object sender, CellEventArgs e);
|
||||
|
||||
public class CellEventArgs
|
||||
{
|
||||
public CellEventArgs(Cell oldCell, Cell newCell)
|
||||
|
@ -124,11 +126,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
public Cell NewCell { get; private set; }
|
||||
}
|
||||
|
||||
public delegate void CellChangeEventHandler(object sender, CellEventArgs e);
|
||||
|
||||
[Category("Mouse")] // TODO: is this the correct name?
|
||||
public event CellChangeEventHandler PointedCellChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
@ -157,60 +154,151 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
#region Paint
|
||||
|
||||
private void DrawColumnBg(GDIRenderer gdi, PaintEventArgs e)
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
gdi.SetBrush(SystemColors.ControlLight);
|
||||
gdi.SetSolidPen(Color.Black);
|
||||
using (var LCK = Gdi.LockGraphics(e.Graphics))
|
||||
{
|
||||
// Header
|
||||
if (Columns.Any())
|
||||
{
|
||||
DrawColumnBg(e);
|
||||
DrawColumnText(e);
|
||||
}
|
||||
|
||||
// Background
|
||||
DrawBg(e);
|
||||
|
||||
// ForeGround
|
||||
DrawData(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||
{
|
||||
// Do nothing, and this should never be called
|
||||
}
|
||||
|
||||
private void DrawColumnText(PaintEventArgs e)
|
||||
{
|
||||
if (HorizontalOrientation)
|
||||
{
|
||||
int start = 0;
|
||||
Gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
foreach (var column in Columns)
|
||||
{
|
||||
var point = new Point(CellPadding, start + CellPadding);
|
||||
Gdi.DrawString(column.Text, point);
|
||||
start += CellHeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int start = CellPadding;
|
||||
Gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
foreach (var column in Columns)
|
||||
{
|
||||
var point = new Point(start + CellPadding, CellPadding);
|
||||
Gdi.DrawString(column.Text, point);
|
||||
start += CalcWidth(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawData(PaintEventArgs e)
|
||||
{
|
||||
if (QueryItemText != null)
|
||||
{
|
||||
if (HorizontalOrientation)
|
||||
{
|
||||
var visibleRows = (Width - _horizontalOrientedColumnWidth) / CellWidth;
|
||||
Gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
for (int i = 0; i < visibleRows; i++)
|
||||
{
|
||||
for (int j = 0; j < Columns.Count; j++)
|
||||
{
|
||||
string text;
|
||||
int x = _horizontalOrientedColumnWidth + CellPadding + (CellWidth * i);
|
||||
int y = j * CellHeight;
|
||||
var point = new Point(x, y);
|
||||
QueryItemText(i, j, out text);
|
||||
Gdi.DrawString(text, point);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var visibleRows = (Height / CellHeight) - 1;
|
||||
Gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
for (int i = 1; i < visibleRows; i++)
|
||||
{
|
||||
int x = 1;
|
||||
for (int j = 0; j < Columns.Count; j++)
|
||||
{
|
||||
string text;
|
||||
var point = new Point(x + CellPadding, i * CellHeight);
|
||||
QueryItemText(i, j, out text);
|
||||
Gdi.DrawString(text, point);
|
||||
x += CalcWidth(Columns[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawColumnBg(PaintEventArgs e)
|
||||
{
|
||||
Gdi.SetBrush(SystemColors.ControlLight);
|
||||
Gdi.SetSolidPen(Color.Black);
|
||||
|
||||
if (HorizontalOrientation)
|
||||
{
|
||||
var colWidth = _horizontalOrientedColumnWidth;
|
||||
gdi.DrawRectangle(0, 0, colWidth, Height);
|
||||
Gdi.DrawRectangle(0, 0, _horizontalOrientedColumnWidth, Height);
|
||||
Gdi.FillRectangle(1, 1, _horizontalOrientedColumnWidth - 3, Height - 3);
|
||||
|
||||
int start = 0;
|
||||
foreach (var column in Columns)
|
||||
{
|
||||
start += CellHeight;
|
||||
gdi.Line(1, start, colWidth - 1, start);
|
||||
Gdi.Line(1, start, _horizontalOrientedColumnWidth - 1, start);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gdi.DrawRectangle(0, 0, Width, CellHeight);
|
||||
gdi.FillRectangle(1, 1, Width - 3, CellHeight - 3);
|
||||
Gdi.DrawRectangle(0, 0, Width, CellHeight);
|
||||
Gdi.FillRectangle(1, 1, Width - 3, CellHeight - 3);
|
||||
|
||||
int start = 0;
|
||||
foreach (var column in Columns)
|
||||
{
|
||||
start += CalcWidth(column);
|
||||
gdi.Line(start, 0, start, CellHeight);
|
||||
Gdi.Line(start, 0, start, CellHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBg(GDIRenderer gdi, PaintEventArgs e)
|
||||
private void DrawBg(PaintEventArgs e)
|
||||
{
|
||||
var startPoint = StartBg();
|
||||
|
||||
gdi.SetBrush(Color.White);
|
||||
gdi.SetSolidPen(Color.Black);
|
||||
gdi.FillRectangle(startPoint.X, startPoint.Y, Width, Height);
|
||||
gdi.DrawRectangle(startPoint.X, startPoint.Y, Width, Height);
|
||||
Gdi.SetBrush(Color.White);
|
||||
Gdi.SetSolidPen(Color.Black);
|
||||
Gdi.FillRectangle(startPoint.X, startPoint.Y, Width, Height);
|
||||
Gdi.DrawRectangle(startPoint.X, startPoint.Y, Width, Height);
|
||||
|
||||
gdi.SetSolidPen(SystemColors.ControlLight);
|
||||
Gdi.SetSolidPen(SystemColors.ControlLight);
|
||||
if (HorizontalOrientation)
|
||||
{
|
||||
// Columns
|
||||
for (int i = 1; i < Width / CellWidth; i++)
|
||||
{
|
||||
var x = _horizontalOrientedColumnWidth + (i * CellWidth);
|
||||
gdi.Line(x, 1, x, Columns.Count * CellHeight);
|
||||
Gdi.Line(x, 1, x, Columns.Count * CellHeight);
|
||||
}
|
||||
|
||||
// Rows
|
||||
for (int i = 1; i < Columns.Count + 1; i++)
|
||||
{
|
||||
gdi.Line(_horizontalOrientedColumnWidth, i * CellHeight, Width - 2, i * CellHeight);
|
||||
Gdi.Line(_horizontalOrientedColumnWidth, i * CellHeight, Width - 2, i * CellHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -221,109 +309,17 @@ namespace BizHawk.Client.EmuHawk
|
|||
foreach (var column in Columns)
|
||||
{
|
||||
x += CalcWidth(column);
|
||||
gdi.Line(x, y, x, Height - 1);
|
||||
Gdi.Line(x, y, x, Height - 1);
|
||||
}
|
||||
|
||||
// Rows
|
||||
for (int i = 2; i < Height / CellHeight; i++)
|
||||
{
|
||||
gdi.Line(1, (i * CellHeight) + 1, Width - 2, (i * CellHeight) + 1);
|
||||
Gdi.Line(1, (i * CellHeight) + 1, Width - 2, (i * CellHeight) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||
{
|
||||
// Do nothing, and this should never be called
|
||||
}
|
||||
|
||||
private void DrawColumnText(GDIRenderer gdi, PaintEventArgs e)
|
||||
{
|
||||
if (HorizontalOrientation)
|
||||
{
|
||||
int start = 0;
|
||||
gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
foreach (var column in Columns)
|
||||
{
|
||||
var point = new Point(CellPadding, start + CellPadding);
|
||||
gdi.DrawString(column.Text, point);
|
||||
start += CellHeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int start = CellPadding;
|
||||
gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
foreach(var column in Columns)
|
||||
{
|
||||
var point = new Point(start + CellPadding, CellPadding);
|
||||
gdi.DrawString(column.Text, point);
|
||||
start += CalcWidth(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawData(GDIRenderer gdi, PaintEventArgs e)
|
||||
{
|
||||
if (QueryItemText != null)
|
||||
{
|
||||
if (HorizontalOrientation)
|
||||
{
|
||||
var visibleRows = (Width - _horizontalOrientedColumnWidth) / CellWidth;
|
||||
gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
for (int i = 0; i < visibleRows; i++)
|
||||
{
|
||||
for (int j = 0; j < Columns.Count; j++)
|
||||
{
|
||||
string text;
|
||||
int x = _horizontalOrientedColumnWidth + CellPadding + (CellWidth * i);
|
||||
int y = j * CellHeight;
|
||||
var point = new Point(x, y);
|
||||
QueryItemText(i, j, out text);
|
||||
gdi.DrawString(text, point);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var visibleRows = (Height / CellHeight) - 1;
|
||||
gdi.PrepDrawString(this.Font, this.ForeColor);
|
||||
for (int i = 1; i < visibleRows; i++)
|
||||
{
|
||||
int x = 1;
|
||||
for (int j = 0; j < Columns.Count; j++)
|
||||
{
|
||||
string text;
|
||||
var point = new Point(x + CellPadding, i * CellHeight);
|
||||
QueryItemText(i, j, out text);
|
||||
gdi.DrawString(text, point);
|
||||
x += CalcWidth(Columns[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ctr;
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
using (var LCK = Gdi.LockGraphics(e.Graphics))
|
||||
{
|
||||
// Header
|
||||
if (Columns.Any())
|
||||
{
|
||||
DrawColumnBg(Gdi, e);
|
||||
DrawColumnText(Gdi, e);
|
||||
}
|
||||
|
||||
// Background
|
||||
DrawBg(Gdi, e);
|
||||
|
||||
// ForeGround
|
||||
DrawData(Gdi, e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mouse and Key Events
|
||||
|
@ -339,6 +335,33 @@ namespace BizHawk.Client.EmuHawk
|
|||
base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
CalculatePointedCell(e.X, e.Y);
|
||||
base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(EventArgs e)
|
||||
{
|
||||
CurrentCell = new Cell
|
||||
{
|
||||
Column = null,
|
||||
RowIndex = null
|
||||
};
|
||||
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
CurrentCell = null;
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void CalculatePointedCell(int x, int y)
|
||||
{
|
||||
var newCell = new Cell();
|
||||
|
@ -390,42 +413,14 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newCell != CurrentCell)
|
||||
|
||||
if (!newCell.Equals(CurrentCell))
|
||||
{
|
||||
CellChanged(CurrentCell, newCell);
|
||||
CurrentCell = newCell;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
CalculatePointedCell(e.X, e.Y);
|
||||
base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(EventArgs e)
|
||||
{
|
||||
CurrentCell = new Cell
|
||||
{
|
||||
Column = null,
|
||||
RowIndex = null
|
||||
};
|
||||
|
||||
base.OnMouseEnter(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
CurrentCell = null;
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void CellChanged(Cell oldCell, Cell newCell)
|
||||
{
|
||||
if (PointedCellChanged != null)
|
||||
|
@ -439,6 +434,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO: Calculate this on Orientation change instead of call it every time
|
||||
private Point StartBg()
|
||||
{
|
||||
if (Columns.Any())
|
||||
|
@ -451,15 +447,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
var x = 0;
|
||||
var y = CellHeight - 1;
|
||||
return new Point(x, y);
|
||||
return new Point(0, y);
|
||||
}
|
||||
}
|
||||
|
||||
return new Point(0, 0);
|
||||
}
|
||||
|
||||
// TODO: calculate this on Cell Padding change instead of calculate it every time
|
||||
private int CellHeight
|
||||
{
|
||||
get
|
||||
|
@ -468,6 +464,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: calculate this on Cell Padding change instead of calculate it every time
|
||||
private int CellWidth
|
||||
{
|
||||
get
|
||||
|
@ -496,6 +493,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
_horizontalOrientedColumnWidth = (text * _charSize.Width) + (CellPadding * 2);
|
||||
}
|
||||
|
||||
// On Column Change calculate this for every column
|
||||
private int CalcWidth(RollColumn col)
|
||||
{
|
||||
return col.Width ?? ((col.Text.Length * _charSize.Width) + (CellPadding * 4));
|
||||
|
|
Loading…
Reference in New Issue