diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
index d323d5241f..ff5c3580d8 100644
--- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
+++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
@@ -566,6 +566,7 @@
CoreFeatureAnalysis.cs
+
Form
@@ -575,7 +576,7 @@
Component
-
+
Component
diff --git a/BizHawk.Client.EmuHawk/CustomControls/GDIRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs
similarity index 96%
rename from BizHawk.Client.EmuHawk/CustomControls/GDIRenderer.cs
rename to BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs
index 92ef9d86c0..e4548f4cca 100644
--- a/BizHawk.Client.EmuHawk/CustomControls/GDIRenderer.cs
+++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs
@@ -1,769 +1,769 @@
-using System;
-using System.Text;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Runtime.InteropServices;
-
-namespace BizHawk.Client.EmuHawk.CustomControls
-{
- ///
- /// Wrapper for GDI rendering functions
- /// This class is not thread-safe as GDI functions should be called from the UI thread
- ///
- public sealed class GDIRenderer : IDisposable
- {
- ///
- /// used for calculation.
- ///
- private static readonly int[] CharFit = new int[1];
-
- ///
- /// used for calculation
- ///
- private static readonly int[] CharFitWidth = new int[1000];
-
- ///
- /// Cache of all the HFONTs used, rather than create them again and again
- ///
- private readonly Dictionary FontsCache = new Dictionary();
-
- class FontCacheEntry
- {
- public IntPtr HFont;
- }
-
- ///
- /// Cache of all the brushes used, rather than create them again and again
- ///
- private readonly Dictionary BrushCache = new Dictionary();
-
- private Graphics _g;
- private IntPtr _hdc;
- private IntPtr _currentBrush = IntPtr.Zero;
-
- #region Construct and Destroy
-
- public GDIRenderer()
- {
- //zero 04-16-2016 : this can't be legal, theres no HDC yet
- //SetBkMode(_hdc, BkModes.OPAQUE);
- }
-
- public void Dispose()
- {
- foreach (var brush in BrushCache)
- {
- if (brush.Value != IntPtr.Zero)
- {
- DeleteObject(brush.Value);
- }
- }
-
- foreach (var fc in FontsCache)
- DeleteObject(fc.Value.HFont);
-
- EndOffScreenBitmap();
-
- System.Diagnostics.Debug.Assert(_hdc == IntPtr.Zero, "Disposed a GDIRenderer while it held an HDC");
- System.Diagnostics.Debug.Assert(_g == null, "Disposed a GDIRenderer while it held a Graphics");
- }
-
- #endregion
-
- #region Api
-
- ///
- /// Draw a bitmap object at the given position
- ///
- public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false)
- {
- IntPtr hbmp = bitmap.GetHbitmap();
- var bitHDC = CreateCompatibleDC(CurrentHDC);
- IntPtr old = SelectObject(bitHDC, hbmp);
- if (blend)
- {
- AlphaBlend(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA));
- }
- else
- {
- BitBlt(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, 0xCC0020);
- }
- SelectObject(bitHDC, old);
- DeleteDC(bitHDC);
- DeleteObject(hbmp);
- }
-
- ///
- /// Required to use before calling drawing methods
- ///
- public GdiGraphicsLock LockGraphics(Graphics g)
- {
- _g = g;
- _hdc = g.GetHdc();
- SetBkMode(_hdc, BkModes.TRANSPARENT);
- return new GdiGraphicsLock(this);
- }
-
- ///
- /// Measure the width and height of string when drawn on device context HDC
- /// using the given font
- ///
- public Size MeasureString(string str, Font font)
- {
- SetFont(font);
-
- var size = new Size();
- GetTextExtentPoint32(CurrentHDC, str, str.Length, ref size);
- return size;
- }
-
- ///
- /// Measure the width and height of string when drawn on device context HDC
- /// using the given 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
- ///
- /// the max width to render the string in
- /// the number of characters that will fit under restriction
- public Size MeasureString(string str, Font font, float maxWidth, out int charFit, out int charFitWidth)
- {
- SetFont(font);
-
- var size = new Size();
- GetTextExtentExPoint(CurrentHDC, str, str.Length, (int)Math.Round(maxWidth), CharFit, CharFitWidth, ref size);
- charFit = CharFit[0];
- charFitWidth = charFit > 0 ? CharFitWidth[charFit - 1] : 0;
- return size;
- }
-
- public void DrawString(string str, Point point)
- {
- TextOut(CurrentHDC, point.X, point.Y, str, str.Length);
- }
-
- public static IntPtr CreateNormalHFont(Font font, int width)
- {
- LOGFONT logf = new LOGFONT();
- font.ToLogFont(logf);
- logf.lfWidth = width;
- logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS;
- var ret = CreateFontIndirect(logf);
- return ret;
- }
-
- //this returns an IntPtr HFONT because .net's Font class will erase the relevant properties when using its Font.FromLogFont()
- //note that whether this is rotated clockwise or CCW might affect how you have to position the text (right-aligned sometimes?, up or down by the height of the font?)
- public static IntPtr CreateRotatedHFont(Font font, bool CW)
- {
- LOGFONT logf = new LOGFONT();
- font.ToLogFont(logf);
- logf.lfEscapement = CW ? 2700 : 900;
- logf.lfOrientation = logf.lfEscapement;
- logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS;
-
- //this doesnt work! .net erases the relevant propreties.. it seems?
- //return Font.FromLogFont(logf);
-
- var ret = CreateFontIndirect(logf);
- return ret;
- }
-
- public static void DestroyHFont(IntPtr hfont)
- {
- DeleteObject(hfont);
- }
-
- public void PrepDrawString(IntPtr hfont, Color color)
- {
- SetGraphicsMode(CurrentHDC, 2); //shouldnt be necessary.. cant hurt
- SelectObject(CurrentHDC, hfont);
- SetTextColor(color);
- }
-
- public void PrepDrawString(Font font, Color color)
- {
- SetFont(font);
- SetTextColor(color);
- }
-
-
- ///
- /// 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]
- ///
- public void DrawString(string str, Font font, Color color, Rectangle rect, TextFormatFlags flags)
- {
- SetFont(font);
- SetTextColor(color);
-
- var rect2 = new Rect(rect);
- DrawText(CurrentHDC, str, str.Length, ref rect2, (uint)flags);
- }
-
-
- ///
- /// Set the text color of the device context
- ///
- public void SetTextColor(Color color)
- {
- int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
- SetTextColor(CurrentHDC, rgb);
- }
-
- public void SetBackgroundColor(Color color)
- {
- int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
- SetBkColor(CurrentHDC, rgb);
- }
-
- public void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
- {
- Rectangle(CurrentHDC, nLeftRect, nTopRect, nRightRect, nBottomRect);
- }
-
- public void SetBrush(Color color)
- {
- if (BrushCache.ContainsKey(color))
- {
- _currentBrush = BrushCache[color];
- }
- else
- {
- int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
- var newBrush = CreateSolidBrush(rgb);
- BrushCache.Add(color, newBrush);
- _currentBrush = newBrush;
- }
- }
-
- public void FillRectangle(int x, int y, int w, int h)
- {
- var r = new GDIRect(new Rectangle(x, y, w, h));
- FillRect(CurrentHDC, ref r, _currentBrush);
- }
-
- public void SetPenPosition(int x, int y)
- {
- MoveToEx(CurrentHDC, x, y, IntPtr.Zero);
- }
-
- public void SetSolidPen(Color color)
- {
- int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
- SelectObject(CurrentHDC, GetStockObject((int)PaintObjects.DC_PEN));
- SetDCPenColor(CurrentHDC, rgb);
- }
-
- public void Line(int x1, int y1, int x2, int y2)
- {
- MoveToEx(CurrentHDC, x1, y1, IntPtr.Zero);
- LineTo(CurrentHDC, x2, y2);
- }
-
- private IntPtr CurrentHDC
- {
- get { return _bitHDC != IntPtr.Zero ? _bitHDC : _hdc; }
- }
-
- private IntPtr _bitMap = IntPtr.Zero;
- private IntPtr _bitHDC = IntPtr.Zero;
- private int _bitW;
- private int _bitH;
-
- public void StartOffScreenBitmap(int width, int height)
- {
- _bitW = width;
- _bitH = height;
-
- _bitHDC = CreateCompatibleDC(_hdc);
- _bitMap = CreateCompatibleBitmap(_hdc, width, height);
- SelectObject(_bitHDC, _bitMap);
- SetBkMode(_bitHDC, BkModes.TRANSPARENT);
- }
-
- public void EndOffScreenBitmap()
- {
- _bitW = 0;
- _bitH = 0;
-
- DeleteObject(_bitMap);
- DeleteObject(_bitHDC);
-
- _bitHDC = IntPtr.Zero;
- _bitMap = IntPtr.Zero;
- }
-
- public void CopyToScreen()
- {
- BitBlt(_hdc, 0, 0, _bitW, _bitH, _bitHDC, 0, 0, 0x00CC0020);
- }
-
- #endregion
-
- #region Helpers
-
- ///
- /// Set a resource (e.g. a font) for the specified device context.
- ///
- private void SetFont(Font font)
- {
- SelectObject(CurrentHDC, GetCachedHFont(font));
- }
-
- private IntPtr GetCachedHFont(Font font)
- {
- //the original code struck me as bad. attempting to ID fonts by picking a subset of their fields is not gonna work.
- //don't call this.Font in InputRoll.cs, it is probably slow.
- //consider Fonts to be a jealously guarded resource (they need to be disposed, after all) and manage them carefully.
- //this cache maintains the HFONTs only.
- FontCacheEntry ce;
- if (!FontsCache.TryGetValue(font, out ce))
- {
- FontsCache[font] = ce = new FontCacheEntry();
- ce.HFont = font.ToHfont();
- }
- return ce.HFont;
- }
-
- #endregion
-
- #region Imports
-
- [DllImport("user32.dll")]
- private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
-
- [DllImport("user32.dll")]
- private static extern IntPtr GetDC(IntPtr hWnd);
-
- [DllImport("user32.dll")]
- private static extern IntPtr BeginPaint(IntPtr hWnd, ref IntPtr lpPaint);
-
- [DllImport("user32.dll")]
- private static extern IntPtr EndPaint(IntPtr hWnd, IntPtr lpPaint);
-
- [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
- private static extern IntPtr CreateFontIndirect(
- [In, MarshalAs(UnmanagedType.LPStruct)]LOGFONT lplf
- );
-
- [DllImport("gdi32.dll")]
- 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);
-
- [DllImport("gdi32.dll")]
- private static extern int SetBkMode(IntPtr hdc, BkModes mode);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj);
-
- [DllImport("gdi32.dll")]
- private static extern int SetTextColor(IntPtr hdc, int color);
-
- [DllImport("gdi32.dll")]
- private static extern int SetBkColor(IntPtr hdc, int color);
-
- [DllImport("gdi32.dll", EntryPoint = "GetTextExtentPoint32W")]
- private static extern int GetTextExtentPoint32(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Size size);
-
- [DllImport("gdi32.dll", EntryPoint = "GetTextExtentExPointW")]
- private static extern bool GetTextExtentExPoint(IntPtr hDc, [MarshalAs(UnmanagedType.LPWStr)]string str, int nLength, int nMaxExtent, int[] lpnFit, int[] alpDx, ref Size size);
-
- [DllImport("gdi32.dll", EntryPoint = "TextOutW")]
- private static extern bool TextOut(IntPtr hdc, int x, int y, [MarshalAs(UnmanagedType.LPWStr)] string str, int len);
-
- [DllImport("gdi32.dll")]
- public static extern int SetGraphicsMode(IntPtr hdc, int iMode);
-
- [DllImport("user32.dll", EntryPoint = "DrawTextW")]
- private static extern int DrawText(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Rect rect, uint uFormat);
-
- [DllImport("gdi32.dll", EntryPoint = "ExtTextOutW")]
- private static extern bool ExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions, uint cbCount, [In] IntPtr lpDx);
-
- [DllImport("gdi32.dll")]
- static extern bool SetWorldTransform(IntPtr hdc, [In] ref XFORM lpXform);
-
- [DllImport("gdi32.dll")]
- private static extern int SelectClipRgn(IntPtr hdc, IntPtr hrgn);
-
- [DllImport("gdi32.dll")]
- private static extern bool DeleteObject(IntPtr hObject);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr CreateSolidBrush(int color);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr CreatePen(int fnPenStyle, int nWidth, int color);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr MoveToEx(IntPtr hdc, int x, int y, IntPtr point);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr LineTo(IntPtr hdc, int nXEnd, int nYEnd);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr GetStockObject(int fnObject);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr SetDCPenColor(IntPtr hdc, int crColor);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
-
- [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
- public static extern bool DeleteDC([In] IntPtr hdc);
-
- [DllImport("gdi32.dll")]
- private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height);
-
- [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
-
- [DllImport("gdi32.dll", EntryPoint = "GdiAlphaBlend")]
- static extern bool AlphaBlend(IntPtr hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction);
-
- public enum FontWeight : int
- {
- FW_DONTCARE = 0,
- FW_THIN = 100,
- FW_EXTRALIGHT = 200,
- FW_LIGHT = 300,
- FW_NORMAL = 400,
- FW_MEDIUM = 500,
- FW_SEMIBOLD = 600,
- FW_BOLD = 700,
- FW_EXTRABOLD = 800,
- FW_HEAVY = 900,
- }
- public enum FontCharSet : byte
- {
- ANSI_CHARSET = 0,
- DEFAULT_CHARSET = 1,
- SYMBOL_CHARSET = 2,
- SHIFTJIS_CHARSET = 128,
- HANGEUL_CHARSET = 129,
- HANGUL_CHARSET = 129,
- GB2312_CHARSET = 134,
- CHINESEBIG5_CHARSET = 136,
- OEM_CHARSET = 255,
- JOHAB_CHARSET = 130,
- HEBREW_CHARSET = 177,
- ARABIC_CHARSET = 178,
- GREEK_CHARSET = 161,
- TURKISH_CHARSET = 162,
- VIETNAMESE_CHARSET = 163,
- THAI_CHARSET = 222,
- EASTEUROPE_CHARSET = 238,
- RUSSIAN_CHARSET = 204,
- MAC_CHARSET = 77,
- BALTIC_CHARSET = 186,
- }
- public enum FontPrecision : byte
- {
- OUT_DEFAULT_PRECIS = 0,
- OUT_STRING_PRECIS = 1,
- OUT_CHARACTER_PRECIS = 2,
- OUT_STROKE_PRECIS = 3,
- OUT_TT_PRECIS = 4,
- OUT_DEVICE_PRECIS = 5,
- OUT_RASTER_PRECIS = 6,
- OUT_TT_ONLY_PRECIS = 7,
- OUT_OUTLINE_PRECIS = 8,
- OUT_SCREEN_OUTLINE_PRECIS = 9,
- OUT_PS_ONLY_PRECIS = 10,
- }
- public enum FontClipPrecision : byte
- {
- CLIP_DEFAULT_PRECIS = 0,
- CLIP_CHARACTER_PRECIS = 1,
- CLIP_STROKE_PRECIS = 2,
- CLIP_MASK = 0xf,
- CLIP_LH_ANGLES = (1 << 4),
- CLIP_TT_ALWAYS = (2 << 4),
- CLIP_DFA_DISABLE = (4 << 4),
- CLIP_EMBEDDED = (8 << 4),
- }
- public enum FontQuality : byte
- {
- DEFAULT_QUALITY = 0,
- DRAFT_QUALITY = 1,
- PROOF_QUALITY = 2,
- NONANTIALIASED_QUALITY = 3,
- ANTIALIASED_QUALITY = 4,
- CLEARTYPE_QUALITY = 5,
- CLEARTYPE_NATURAL_QUALITY = 6,
- }
- [Flags]
- public enum FontPitchAndFamily : byte
- {
- DEFAULT_PITCH = 0,
- FIXED_PITCH = 1,
- VARIABLE_PITCH = 2,
- FF_DONTCARE = (0 << 4),
- FF_ROMAN = (1 << 4),
- FF_SWISS = (2 << 4),
- FF_MODERN = (3 << 4),
- FF_SCRIPT = (4 << 4),
- FF_DECORATIVE = (5 << 4),
- }
-
- //it is important for this to be the right declaration
- //see more here http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2004-04/0319.html
- //if it's wrong (I had a wrong one from pinvoke.net) then ToLogFont will fail mysteriously
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- class LOGFONT
- {
- public int lfHeight = 0;
- public int lfWidth = 0;
- public int lfEscapement = 0;
- public int lfOrientation = 0;
- public int lfWeight = 0;
- public byte lfItalic = 0;
- public byte lfUnderline = 0;
- public byte lfStrikeOut = 0;
- public byte lfCharSet = 0;
- public byte lfOutPrecision = 0;
- public byte lfClipPrecision = 0;
- public byte lfQuality = 0;
- public byte lfPitchAndFamily = 0;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
- public string lfFaceName = null;
- }
-
- ///
- /// The graphics mode that can be set by SetGraphicsMode.
- ///
- public enum GraphicsMode : int
- {
- ///
- /// Sets the graphics mode that is compatible with 16-bit Windows. This is the default mode. If
- /// this value is specified, the application can only modify the world-to-device transform by
- /// calling functions that set window and viewport extents and origins, but not by using
- /// SetWorldTransform or ModifyWorldTransform; calls to those functions will fail.
- /// Examples of functions that set window and viewport extents and origins are SetViewportExtEx
- /// and SetWindowExtEx.
- ///
- GM_COMPATIBLE = 1,
- ///
- /// Sets the advanced graphics mode that allows world transformations. This value must be
- /// specified if the application will set or modify the world transformation for the specified
- /// device context. In this mode all graphics, including text output, fully conform to the
- /// world-to-device transformation specified in the device context.
- ///
- GM_ADVANCED = 2,
- }
-
- ///
- /// The XFORM structure specifies a world-space to page-space transformation.
- ///
- [StructLayout(LayoutKind.Sequential)]
- public struct XFORM
- {
- public float eM11;
- public float eM12;
- public float eM21;
- public float eM22;
- public float eDx;
- public float eDy;
-
- public XFORM(float eM11, float eM12, float eM21, float eM22, float eDx, float eDy)
- {
- this.eM11 = eM11;
- this.eM12 = eM12;
- this.eM21 = eM21;
- this.eM22 = eM22;
- this.eDx = eDx;
- this.eDy = eDy;
- }
-
- ///
- /// Allows implicit converstion to a managed transformation matrix.
- ///
- public static implicit operator System.Drawing.Drawing2D.Matrix(XFORM xf)
- {
- return new System.Drawing.Drawing2D.Matrix(xf.eM11, xf.eM12, xf.eM21, xf.eM22, xf.eDx, xf.eDy);
- }
-
- ///
- /// Allows implicit converstion from a managed transformation matrix.
- ///
- public static implicit operator XFORM(System.Drawing.Drawing2D.Matrix m)
- {
- float[] elems = m.Elements;
- return new XFORM(elems[0], elems[1], elems[2], elems[3], elems[4], elems[5]);
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct BLENDFUNCTION
- {
- byte BlendOp;
- byte BlendFlags;
- byte SourceConstantAlpha;
- byte AlphaFormat;
-
- public BLENDFUNCTION(byte op, byte flags, byte alpha, byte format)
- {
- BlendOp = op;
- BlendFlags = flags;
- SourceConstantAlpha = alpha;
- AlphaFormat = format;
- }
- }
-
- const byte AC_SRC_OVER = 0x00;
- const byte AC_SRC_ALPHA = 0x01;
-
- [DllImport("gdi32.dll")]
- static extern int SetBitmapBits(IntPtr hbmp, uint cBytes, byte[] lpBits);
-
- #endregion
-
- #region Classes, Structs, and Enums
-
- public class GdiGraphicsLock : IDisposable
- {
- private readonly GDIRenderer Gdi;
-
- public GdiGraphicsLock(GDIRenderer gdi)
- {
- this.Gdi = gdi;
- }
-
- 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;
- }
- }
-
- [Flags]
- public enum ETOOptions : uint
- {
- CLIPPED = 0x4,
- GLYPH_INDEX = 0x10,
- IGNORELANGUAGE = 0x1000,
- NUMERICSLATIN = 0x800,
- NUMERICSLOCAL = 0x400,
- OPAQUE = 0x2,
- PDY = 0x2000,
- RTLREADING = 0x800,
- }
-
- ///
- /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15]
- ///
- [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 : int
- {
- TRANSPARENT = 1,
- OPAQUE = 2
- }
-
- #endregion
- }
-}
+using System;
+using System.Text;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+namespace BizHawk.Client.EmuHawk.CustomControls
+{
+ ///
+ /// Wrapper for GDI rendering functions
+ /// This class is not thread-safe as GDI functions should be called from the UI thread
+ ///
+ public sealed class GDIRenderer : IControlRenderer
+ {
+ ///
+ /// used for calculation.
+ ///
+ private static readonly int[] CharFit = new int[1];
+
+ ///
+ /// used for calculation
+ ///
+ private static readonly int[] CharFitWidth = new int[1000];
+
+ ///
+ /// Cache of all the HFONTs used, rather than create them again and again
+ ///
+ private readonly Dictionary FontsCache = new Dictionary();
+
+ class FontCacheEntry
+ {
+ public IntPtr HFont;
+ }
+
+ ///
+ /// Cache of all the brushes used, rather than create them again and again
+ ///
+ private readonly Dictionary BrushCache = new Dictionary();
+
+ private Graphics _g;
+ private IntPtr _hdc;
+ private IntPtr _currentBrush = IntPtr.Zero;
+
+ #region Construct and Destroy
+
+ public GDIRenderer()
+ {
+ //zero 04-16-2016 : this can't be legal, theres no HDC yet
+ //SetBkMode(_hdc, BkModes.OPAQUE);
+ }
+
+ public void Dispose()
+ {
+ foreach (var brush in BrushCache)
+ {
+ if (brush.Value != IntPtr.Zero)
+ {
+ DeleteObject(brush.Value);
+ }
+ }
+
+ foreach (var fc in FontsCache)
+ DeleteObject(fc.Value.HFont);
+
+ EndOffScreenBitmap();
+
+ System.Diagnostics.Debug.Assert(_hdc == IntPtr.Zero, "Disposed a GDIRenderer while it held an HDC");
+ System.Diagnostics.Debug.Assert(_g == null, "Disposed a GDIRenderer while it held a Graphics");
+ }
+
+ #endregion
+
+ #region Api
+
+ ///
+ /// Draw a bitmap object at the given position
+ ///
+ public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false)
+ {
+ IntPtr hbmp = bitmap.GetHbitmap();
+ var bitHDC = CreateCompatibleDC(CurrentHDC);
+ IntPtr old = SelectObject(bitHDC, hbmp);
+ if (blend)
+ {
+ AlphaBlend(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA));
+ }
+ else
+ {
+ BitBlt(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, 0xCC0020);
+ }
+ SelectObject(bitHDC, old);
+ DeleteDC(bitHDC);
+ DeleteObject(hbmp);
+ }
+
+ ///
+ /// Required to use before calling drawing methods
+ ///
+ public IDisposable LockGraphics(Graphics g)
+ {
+ _g = g;
+ _hdc = g.GetHdc();
+ SetBkMode(_hdc, BkModes.TRANSPARENT);
+ return new GdiGraphicsLock(this);
+ }
+
+ ///
+ /// Measure the width and height of string when drawn on device context HDC
+ /// using the given font
+ ///
+ public Size MeasureString(string str, Font font)
+ {
+ SetFont(font);
+
+ var size = new Size();
+ GetTextExtentPoint32(CurrentHDC, str, str.Length, ref size);
+ return size;
+ }
+
+ ///
+ /// Measure the width and height of string when drawn on device context HDC
+ /// using the given 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
+ ///
+ /// the max width to render the string in
+ /// the number of characters that will fit under restriction
+ public Size MeasureString(string str, Font font, float maxWidth, out int charFit, out int charFitWidth)
+ {
+ SetFont(font);
+
+ var size = new Size();
+ GetTextExtentExPoint(CurrentHDC, str, str.Length, (int)Math.Round(maxWidth), CharFit, CharFitWidth, ref size);
+ charFit = CharFit[0];
+ charFitWidth = charFit > 0 ? CharFitWidth[charFit - 1] : 0;
+ return size;
+ }
+
+ public void DrawString(string str, Point point)
+ {
+ TextOut(CurrentHDC, point.X, point.Y, str, str.Length);
+ }
+
+ public static IntPtr CreateNormalHFont(Font font, int width)
+ {
+ LOGFONT logf = new LOGFONT();
+ font.ToLogFont(logf);
+ logf.lfWidth = width;
+ logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS;
+ var ret = CreateFontIndirect(logf);
+ return ret;
+ }
+
+ //this returns an IntPtr HFONT because .net's Font class will erase the relevant properties when using its Font.FromLogFont()
+ //note that whether this is rotated clockwise or CCW might affect how you have to position the text (right-aligned sometimes?, up or down by the height of the font?)
+ public static IntPtr CreateRotatedHFont(Font font, bool CW)
+ {
+ LOGFONT logf = new LOGFONT();
+ font.ToLogFont(logf);
+ logf.lfEscapement = CW ? 2700 : 900;
+ logf.lfOrientation = logf.lfEscapement;
+ logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS;
+
+ //this doesnt work! .net erases the relevant propreties.. it seems?
+ //return Font.FromLogFont(logf);
+
+ var ret = CreateFontIndirect(logf);
+ return ret;
+ }
+
+ public static void DestroyHFont(IntPtr hfont)
+ {
+ DeleteObject(hfont);
+ }
+
+ public void PrepDrawString(IntPtr hfont, Color color)
+ {
+ SetGraphicsMode(CurrentHDC, 2); //shouldnt be necessary.. cant hurt
+ SelectObject(CurrentHDC, hfont);
+ SetTextColor(color);
+ }
+
+ public void PrepDrawString(Font font, Color color)
+ {
+ SetFont(font);
+ SetTextColor(color);
+ }
+
+
+ ///
+ /// 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]
+ ///
+ public void DrawString(string str, Font font, Color color, Rectangle rect, TextFormatFlags flags)
+ {
+ SetFont(font);
+ SetTextColor(color);
+
+ var rect2 = new Rect(rect);
+ DrawText(CurrentHDC, str, str.Length, ref rect2, (uint)flags);
+ }
+
+
+ ///
+ /// Set the text color of the device context
+ ///
+ public void SetTextColor(Color color)
+ {
+ int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
+ SetTextColor(CurrentHDC, rgb);
+ }
+
+ public void SetBackgroundColor(Color color)
+ {
+ int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
+ SetBkColor(CurrentHDC, rgb);
+ }
+
+ public void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
+ {
+ Rectangle(CurrentHDC, nLeftRect, nTopRect, nRightRect, nBottomRect);
+ }
+
+ public void SetBrush(Color color)
+ {
+ if (BrushCache.ContainsKey(color))
+ {
+ _currentBrush = BrushCache[color];
+ }
+ else
+ {
+ int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
+ var newBrush = CreateSolidBrush(rgb);
+ BrushCache.Add(color, newBrush);
+ _currentBrush = newBrush;
+ }
+ }
+
+ public void FillRectangle(int x, int y, int w, int h)
+ {
+ var r = new GDIRect(new Rectangle(x, y, w, h));
+ FillRect(CurrentHDC, ref r, _currentBrush);
+ }
+
+ public void SetPenPosition(int x, int y)
+ {
+ MoveToEx(CurrentHDC, x, y, IntPtr.Zero);
+ }
+
+ public void SetSolidPen(Color color)
+ {
+ int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R;
+ SelectObject(CurrentHDC, GetStockObject((int)PaintObjects.DC_PEN));
+ SetDCPenColor(CurrentHDC, rgb);
+ }
+
+ public void Line(int x1, int y1, int x2, int y2)
+ {
+ MoveToEx(CurrentHDC, x1, y1, IntPtr.Zero);
+ LineTo(CurrentHDC, x2, y2);
+ }
+
+ private IntPtr CurrentHDC
+ {
+ get { return _bitHDC != IntPtr.Zero ? _bitHDC : _hdc; }
+ }
+
+ private IntPtr _bitMap = IntPtr.Zero;
+ private IntPtr _bitHDC = IntPtr.Zero;
+ private int _bitW;
+ private int _bitH;
+
+ public void StartOffScreenBitmap(int width, int height)
+ {
+ _bitW = width;
+ _bitH = height;
+
+ _bitHDC = CreateCompatibleDC(_hdc);
+ _bitMap = CreateCompatibleBitmap(_hdc, width, height);
+ SelectObject(_bitHDC, _bitMap);
+ SetBkMode(_bitHDC, BkModes.TRANSPARENT);
+ }
+
+ public void EndOffScreenBitmap()
+ {
+ _bitW = 0;
+ _bitH = 0;
+
+ DeleteObject(_bitMap);
+ DeleteObject(_bitHDC);
+
+ _bitHDC = IntPtr.Zero;
+ _bitMap = IntPtr.Zero;
+ }
+
+ public void CopyToScreen()
+ {
+ BitBlt(_hdc, 0, 0, _bitW, _bitH, _bitHDC, 0, 0, 0x00CC0020);
+ }
+
+ #endregion
+
+ #region Helpers
+
+ ///
+ /// Set a resource (e.g. a font) for the specified device context.
+ ///
+ private void SetFont(Font font)
+ {
+ SelectObject(CurrentHDC, GetCachedHFont(font));
+ }
+
+ private IntPtr GetCachedHFont(Font font)
+ {
+ //the original code struck me as bad. attempting to ID fonts by picking a subset of their fields is not gonna work.
+ //don't call this.Font in InputRoll.cs, it is probably slow.
+ //consider Fonts to be a jealously guarded resource (they need to be disposed, after all) and manage them carefully.
+ //this cache maintains the HFONTs only.
+ FontCacheEntry ce;
+ if (!FontsCache.TryGetValue(font, out ce))
+ {
+ FontsCache[font] = ce = new FontCacheEntry();
+ ce.HFont = font.ToHfont();
+ }
+ return ce.HFont;
+ }
+
+ #endregion
+
+ #region Imports
+
+ [DllImport("user32.dll")]
+ private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr GetDC(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr BeginPaint(IntPtr hWnd, ref IntPtr lpPaint);
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr EndPaint(IntPtr hWnd, IntPtr lpPaint);
+
+ [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
+ private static extern IntPtr CreateFontIndirect(
+ [In, MarshalAs(UnmanagedType.LPStruct)]LOGFONT lplf
+ );
+
+ [DllImport("gdi32.dll")]
+ 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);
+
+ [DllImport("gdi32.dll")]
+ private static extern int SetBkMode(IntPtr hdc, BkModes mode);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj);
+
+ [DllImport("gdi32.dll")]
+ private static extern int SetTextColor(IntPtr hdc, int color);
+
+ [DllImport("gdi32.dll")]
+ private static extern int SetBkColor(IntPtr hdc, int color);
+
+ [DllImport("gdi32.dll", EntryPoint = "GetTextExtentPoint32W")]
+ private static extern int GetTextExtentPoint32(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Size size);
+
+ [DllImport("gdi32.dll", EntryPoint = "GetTextExtentExPointW")]
+ private static extern bool GetTextExtentExPoint(IntPtr hDc, [MarshalAs(UnmanagedType.LPWStr)]string str, int nLength, int nMaxExtent, int[] lpnFit, int[] alpDx, ref Size size);
+
+ [DllImport("gdi32.dll", EntryPoint = "TextOutW")]
+ private static extern bool TextOut(IntPtr hdc, int x, int y, [MarshalAs(UnmanagedType.LPWStr)] string str, int len);
+
+ [DllImport("gdi32.dll")]
+ public static extern int SetGraphicsMode(IntPtr hdc, int iMode);
+
+ [DllImport("user32.dll", EntryPoint = "DrawTextW")]
+ private static extern int DrawText(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Rect rect, uint uFormat);
+
+ [DllImport("gdi32.dll", EntryPoint = "ExtTextOutW")]
+ private static extern bool ExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions, uint cbCount, [In] IntPtr lpDx);
+
+ [DllImport("gdi32.dll")]
+ static extern bool SetWorldTransform(IntPtr hdc, [In] ref XFORM lpXform);
+
+ [DllImport("gdi32.dll")]
+ private static extern int SelectClipRgn(IntPtr hdc, IntPtr hrgn);
+
+ [DllImport("gdi32.dll")]
+ private static extern bool DeleteObject(IntPtr hObject);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr CreateSolidBrush(int color);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr CreatePen(int fnPenStyle, int nWidth, int color);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr MoveToEx(IntPtr hdc, int x, int y, IntPtr point);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr LineTo(IntPtr hdc, int nXEnd, int nYEnd);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr GetStockObject(int fnObject);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr SetDCPenColor(IntPtr hdc, int crColor);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
+
+ [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
+ public static extern bool DeleteDC([In] IntPtr hdc);
+
+ [DllImport("gdi32.dll")]
+ private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height);
+
+ [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
+
+ [DllImport("gdi32.dll", EntryPoint = "GdiAlphaBlend")]
+ static extern bool AlphaBlend(IntPtr hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction);
+
+ public enum FontWeight : int
+ {
+ FW_DONTCARE = 0,
+ FW_THIN = 100,
+ FW_EXTRALIGHT = 200,
+ FW_LIGHT = 300,
+ FW_NORMAL = 400,
+ FW_MEDIUM = 500,
+ FW_SEMIBOLD = 600,
+ FW_BOLD = 700,
+ FW_EXTRABOLD = 800,
+ FW_HEAVY = 900,
+ }
+ public enum FontCharSet : byte
+ {
+ ANSI_CHARSET = 0,
+ DEFAULT_CHARSET = 1,
+ SYMBOL_CHARSET = 2,
+ SHIFTJIS_CHARSET = 128,
+ HANGEUL_CHARSET = 129,
+ HANGUL_CHARSET = 129,
+ GB2312_CHARSET = 134,
+ CHINESEBIG5_CHARSET = 136,
+ OEM_CHARSET = 255,
+ JOHAB_CHARSET = 130,
+ HEBREW_CHARSET = 177,
+ ARABIC_CHARSET = 178,
+ GREEK_CHARSET = 161,
+ TURKISH_CHARSET = 162,
+ VIETNAMESE_CHARSET = 163,
+ THAI_CHARSET = 222,
+ EASTEUROPE_CHARSET = 238,
+ RUSSIAN_CHARSET = 204,
+ MAC_CHARSET = 77,
+ BALTIC_CHARSET = 186,
+ }
+ public enum FontPrecision : byte
+ {
+ OUT_DEFAULT_PRECIS = 0,
+ OUT_STRING_PRECIS = 1,
+ OUT_CHARACTER_PRECIS = 2,
+ OUT_STROKE_PRECIS = 3,
+ OUT_TT_PRECIS = 4,
+ OUT_DEVICE_PRECIS = 5,
+ OUT_RASTER_PRECIS = 6,
+ OUT_TT_ONLY_PRECIS = 7,
+ OUT_OUTLINE_PRECIS = 8,
+ OUT_SCREEN_OUTLINE_PRECIS = 9,
+ OUT_PS_ONLY_PRECIS = 10,
+ }
+ public enum FontClipPrecision : byte
+ {
+ CLIP_DEFAULT_PRECIS = 0,
+ CLIP_CHARACTER_PRECIS = 1,
+ CLIP_STROKE_PRECIS = 2,
+ CLIP_MASK = 0xf,
+ CLIP_LH_ANGLES = (1 << 4),
+ CLIP_TT_ALWAYS = (2 << 4),
+ CLIP_DFA_DISABLE = (4 << 4),
+ CLIP_EMBEDDED = (8 << 4),
+ }
+ public enum FontQuality : byte
+ {
+ DEFAULT_QUALITY = 0,
+ DRAFT_QUALITY = 1,
+ PROOF_QUALITY = 2,
+ NONANTIALIASED_QUALITY = 3,
+ ANTIALIASED_QUALITY = 4,
+ CLEARTYPE_QUALITY = 5,
+ CLEARTYPE_NATURAL_QUALITY = 6,
+ }
+ [Flags]
+ public enum FontPitchAndFamily : byte
+ {
+ DEFAULT_PITCH = 0,
+ FIXED_PITCH = 1,
+ VARIABLE_PITCH = 2,
+ FF_DONTCARE = (0 << 4),
+ FF_ROMAN = (1 << 4),
+ FF_SWISS = (2 << 4),
+ FF_MODERN = (3 << 4),
+ FF_SCRIPT = (4 << 4),
+ FF_DECORATIVE = (5 << 4),
+ }
+
+ //it is important for this to be the right declaration
+ //see more here http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2004-04/0319.html
+ //if it's wrong (I had a wrong one from pinvoke.net) then ToLogFont will fail mysteriously
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ class LOGFONT
+ {
+ public int lfHeight = 0;
+ public int lfWidth = 0;
+ public int lfEscapement = 0;
+ public int lfOrientation = 0;
+ public int lfWeight = 0;
+ public byte lfItalic = 0;
+ public byte lfUnderline = 0;
+ public byte lfStrikeOut = 0;
+ public byte lfCharSet = 0;
+ public byte lfOutPrecision = 0;
+ public byte lfClipPrecision = 0;
+ public byte lfQuality = 0;
+ public byte lfPitchAndFamily = 0;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
+ public string lfFaceName = null;
+ }
+
+ ///
+ /// The graphics mode that can be set by SetGraphicsMode.
+ ///
+ public enum GraphicsMode : int
+ {
+ ///
+ /// Sets the graphics mode that is compatible with 16-bit Windows. This is the default mode. If
+ /// this value is specified, the application can only modify the world-to-device transform by
+ /// calling functions that set window and viewport extents and origins, but not by using
+ /// SetWorldTransform or ModifyWorldTransform; calls to those functions will fail.
+ /// Examples of functions that set window and viewport extents and origins are SetViewportExtEx
+ /// and SetWindowExtEx.
+ ///
+ GM_COMPATIBLE = 1,
+ ///
+ /// Sets the advanced graphics mode that allows world transformations. This value must be
+ /// specified if the application will set or modify the world transformation for the specified
+ /// device context. In this mode all graphics, including text output, fully conform to the
+ /// world-to-device transformation specified in the device context.
+ ///
+ GM_ADVANCED = 2,
+ }
+
+ ///
+ /// The XFORM structure specifies a world-space to page-space transformation.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct XFORM
+ {
+ public float eM11;
+ public float eM12;
+ public float eM21;
+ public float eM22;
+ public float eDx;
+ public float eDy;
+
+ public XFORM(float eM11, float eM12, float eM21, float eM22, float eDx, float eDy)
+ {
+ this.eM11 = eM11;
+ this.eM12 = eM12;
+ this.eM21 = eM21;
+ this.eM22 = eM22;
+ this.eDx = eDx;
+ this.eDy = eDy;
+ }
+
+ ///
+ /// Allows implicit converstion to a managed transformation matrix.
+ ///
+ public static implicit operator System.Drawing.Drawing2D.Matrix(XFORM xf)
+ {
+ return new System.Drawing.Drawing2D.Matrix(xf.eM11, xf.eM12, xf.eM21, xf.eM22, xf.eDx, xf.eDy);
+ }
+
+ ///
+ /// Allows implicit converstion from a managed transformation matrix.
+ ///
+ public static implicit operator XFORM(System.Drawing.Drawing2D.Matrix m)
+ {
+ float[] elems = m.Elements;
+ return new XFORM(elems[0], elems[1], elems[2], elems[3], elems[4], elems[5]);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct BLENDFUNCTION
+ {
+ byte BlendOp;
+ byte BlendFlags;
+ byte SourceConstantAlpha;
+ byte AlphaFormat;
+
+ public BLENDFUNCTION(byte op, byte flags, byte alpha, byte format)
+ {
+ BlendOp = op;
+ BlendFlags = flags;
+ SourceConstantAlpha = alpha;
+ AlphaFormat = format;
+ }
+ }
+
+ const byte AC_SRC_OVER = 0x00;
+ const byte AC_SRC_ALPHA = 0x01;
+
+ [DllImport("gdi32.dll")]
+ static extern int SetBitmapBits(IntPtr hbmp, uint cBytes, byte[] lpBits);
+
+ #endregion
+
+ #region Classes, Structs, and Enums
+
+ public class GdiGraphicsLock : IDisposable
+ {
+ private readonly GDIRenderer Gdi;
+
+ public GdiGraphicsLock(GDIRenderer gdi)
+ {
+ this.Gdi = gdi;
+ }
+
+ 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;
+ }
+ }
+
+ [Flags]
+ public enum ETOOptions : uint
+ {
+ CLIPPED = 0x4,
+ GLYPH_INDEX = 0x10,
+ IGNORELANGUAGE = 0x1000,
+ NUMERICSLATIN = 0x800,
+ NUMERICSLOCAL = 0x400,
+ OPAQUE = 0x2,
+ PDY = 0x2000,
+ RTLREADING = 0x800,
+ }
+
+ ///
+ /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15]
+ ///
+ [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 : int
+ {
+ TRANSPARENT = 1,
+ OPAQUE = 2
+ }
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs
new file mode 100644
index 0000000000..e3c232113c
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Drawing;
+
+namespace BizHawk.Client.EmuHawk.CustomControls
+{
+ public interface IControlRenderer : IDisposable
+ {
+ IDisposable LockGraphics(Graphics g);
+
+ void StartOffScreenBitmap(int width, int height);
+ void EndOffScreenBitmap();
+ void CopyToScreen();
+
+ Size MeasureString(string str, Font font);
+
+ void SetBrush(Color color);
+ void SetSolidPen(Color color);
+
+ // TODO: use the Font version
+ void PrepDrawString(IntPtr hFont, Color color);
+ void DrawString(string str, Point point);
+
+ void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
+ void FillRectangle(int x, int y, int w, int h);
+ void DrawBitmap(Bitmap bitmap, Point point, bool blend = false);
+ void Line(int x1, int y1, int x2, int y2);
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs
index fabf42d68e..9525cbb9ea 100644
--- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs
+++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs
@@ -15,7 +15,7 @@ namespace BizHawk.Client.EmuHawk
// Row width is specified for horizontal orientation
public partial class InputRoll : Control
{
- private readonly GDIRenderer _gdi;
+ private readonly IControlRenderer _gdi;
private readonly SortedSet _selectedItems = new SortedSet(new SortCell());
private readonly VScrollBar _vBar;
| |