do some work which _should_ have supported rotated text. not sure why it isn't working though...

This commit is contained in:
zeromus 2014-10-22 07:59:06 +00:00
parent a7491f4e8f
commit a2722ae10f
2 changed files with 289 additions and 44 deletions

View File

@ -1,4 +1,5 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
@ -22,9 +23,14 @@ namespace BizHawk.Client.EmuHawk.CustomControls
private static readonly int[] CharFitWidth = new int[1000];
/// <summary>
/// Cache of all the fonts used, rather than create them again and again
/// Cache of all the HFONTs 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);
private static readonly Dictionary<Font, FontCacheEntry> FontsCache = new Dictionary<Font, FontCacheEntry>();
class FontCacheEntry
{
public IntPtr HFont;
}
/// <summary>
/// Cache of all the brushes used, rather than create them again and again
@ -52,6 +58,9 @@ namespace BizHawk.Client.EmuHawk.CustomControls
}
}
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");
@ -69,7 +78,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls
{
IntPtr hbmp = bitmap.GetHbitmap();
var bitHDC = CreateCompatibleDC(CurrentHDC);
IntPtr old = new IntPtr(SelectObject(bitHDC, hbmp));
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));
@ -132,12 +141,44 @@ namespace BizHawk.Client.EmuHawk.CustomControls
TextOut(CurrentHDC, point.X, point.Y, str, str.Length);
}
//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.lfFaceName = "System";
logf.lfEscapement = 3600 - 450;
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(ref 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(_hdc, hfont);
SetTextColor(color);
}
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]
@ -151,6 +192,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls
DrawText(CurrentHDC, str, str.Length, ref rect2, (uint)flags);
}
/// <summary>
/// Set the text color of the device context
/// </summary>
@ -262,32 +304,17 @@ namespace BizHawk.Client.EmuHawk.CustomControls
private static IntPtr GetCachedHFont(Font font)
{
var hfont = IntPtr.Zero;
Dictionary<float, Dictionary<FontStyle, IntPtr>> dic1;
if (FontsCache.TryGetValue(font.Name, out dic1))
//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))
{
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>();
}
FontsCache[font] = ce = new FontCacheEntry();
ce.HFont = font.ToHfont();
}
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;
return ce.HFont;
}
#endregion
@ -306,6 +333,9 @@ namespace BizHawk.Client.EmuHawk.CustomControls
[DllImport("user32.dll")]
private static extern IntPtr EndPaint(IntPtr hWnd, IntPtr lpPaint);
[DllImport("gdi32.dll")]
static extern IntPtr CreateFontIndirect([In] ref LOGFONT lplf);
[DllImport("gdi32.dll")]
private static extern int Rectangle(IntPtr hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
@ -316,7 +346,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls
private static extern int SetBkMode(IntPtr hdc, BkModes mode);
[DllImport("gdi32.dll")]
private static extern int SelectObject(IntPtr hdc, IntPtr hgdiObj);
private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj);
[DllImport("gdi32.dll")]
private static extern int SetTextColor(IntPtr hdc, int color);
@ -333,9 +363,18 @@ namespace BizHawk.Client.EmuHawk.CustomControls
[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);
@ -375,6 +414,178 @@ namespace BizHawk.Client.EmuHawk.CustomControls
[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;
}
/// <summary>
/// The graphics mode that can be set by SetGraphicsMode.
/// </summary>
public enum GraphicsMode : int
{
/// <summary>
/// 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.
/// </summary>
GM_COMPATIBLE = 1,
/// <summary>
/// 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.
/// </summary>
GM_ADVANCED = 2,
}
/// <summary>
/// The XFORM structure specifies a world-space to page-space transformation.
/// </summary>
[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;
}
/// <summary>
/// Allows implicit converstion to a managed transformation matrix.
/// </summary>
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);
}
/// <summary>
/// Allows implicit converstion from a managed transformation matrix.
/// </summary>
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
@ -464,6 +675,19 @@ namespace BizHawk.Client.EmuHawk.CustomControls
}
}
[Flags]
public enum ETOOptions : uint
{
CLIPPED = 0x4,
GLYPH_INDEX = 0x10,
IGNORELANGUAGE = 0x1000,
NUMERICSLATIN = 0x800,
NUMERICSLOCAL = 0x400,
OPAQUE = 0x2,
PDY = 0x2000,
RTLREADING = 0x800,
}
/// <summary>
/// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15]
/// </summary>

View File

@ -1,4 +1,6 @@
using System;
//TODO - do not constantly reference this.ForeColor and this.NormalFont. it should be a waste of time. Cache them (and be sure to respond to system messages when the user settings change)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
@ -34,6 +36,9 @@ namespace BizHawk.Client.EmuHawk
private int? _currentX;
private int? _currentY;
private IntPtr RotatedFont;
private Font NormalFont;
public InputRoll()
{
@ -42,7 +47,10 @@ namespace BizHawk.Client.EmuHawk
CellWidthPadding = 3;
CellHeightPadding = 1;
CurrentCell = null;
Font = new Font("Courier New", 8); // Only support fixed width
NormalFont = new Font("Courier New", 8); // Only support fixed width
RotatedFont = GDIRenderer.CreateRotatedHFont(Font, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.UserPaint, true);
@ -54,7 +62,7 @@ namespace BizHawk.Client.EmuHawk
using (var g = CreateGraphics())
using (var LCK = Gdi.LockGraphics(g))
{
_charSize = Gdi.MeasureString("A", this.Font); // TODO make this a property so changing it updates other values.
_charSize = Gdi.MeasureString("A", this.NormalFont); // TODO make this a property so changing it updates other values.
}
UpdateCellSize();
@ -95,6 +103,10 @@ namespace BizHawk.Client.EmuHawk
protected override void Dispose(bool disposing)
{
Gdi.Dispose();
this.NormalFont.Dispose();
GDIRenderer.DestroyHFont(RotatedFont);
base.Dispose(disposing);
}
@ -666,7 +678,7 @@ namespace BizHawk.Client.EmuHawk
Gdi.SetSolidPen(this.BackColor);
Gdi.DrawRectangle(x1, y1, x2, y2);
Gdi.PrepDrawString(this.Font, this.ForeColor);
Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
Gdi.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding));
}
}
@ -678,16 +690,18 @@ namespace BizHawk.Client.EmuHawk
if (HorizontalOrientation)
{
int start = 0;
Gdi.PrepDrawString(this.Font, this.ForeColor);
Gdi.PrepDrawString(this.RotatedFont, this.ForeColor);
foreach (var column in columns)
{
var point = new Point(CellWidthPadding, start + CellHeightPadding);
if (IsHoveringOnColumnCell && column == CurrentCell.Column)
{
Gdi.PrepDrawString(this.Font, SystemColors.HighlightText);
Gdi.PrepDrawString(this.NormalFont, SystemColors.HighlightText);
Gdi.DrawString(column.Text, point);
Gdi.PrepDrawString(this.Font, this.ForeColor);
Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
}
else
{
@ -699,16 +713,23 @@ namespace BizHawk.Client.EmuHawk
}
else
{
Gdi.PrepDrawString(this.Font, this.ForeColor);
//zeromus test
//Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
Gdi.PrepDrawString(this.RotatedFont, this.ForeColor);
foreach (var column in columns)
{
var point = new Point(column.Left.Value + 2 * CellWidthPadding - HBar.Value, CellHeightPadding); // TODO: fix this CellPadding issue (2 * CellPadding vs just CellPadding)
if (IsHoveringOnColumnCell && column == CurrentCell.Column)
{
Gdi.PrepDrawString(this.Font, SystemColors.HighlightText);
//zeromus test
//Gdi.PrepDrawString(this.NormalFont, SystemColors.HighlightText);
Gdi.PrepDrawString(this.RotatedFont, SystemColors.HighlightText);
Gdi.DrawString(column.Text, point);
Gdi.PrepDrawString(this.Font, this.ForeColor);
//zeromus test
//Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
Gdi.PrepDrawString(this.RotatedFont, this.ForeColor);
}
else
{
@ -728,7 +749,7 @@ namespace BizHawk.Client.EmuHawk
int startRow = FirstVisibleRow;
int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1;
Gdi.PrepDrawString(this.Font, this.ForeColor);
Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
for (int i = 0; i < range; i++)
{
for (int j = 0; j < columns.Count; j++)
@ -762,7 +783,7 @@ namespace BizHawk.Client.EmuHawk
var rePrep = false;
if (SelectedItems.Contains(new Cell { Column = columns[j], RowIndex = i + startRow }))
{
Gdi.PrepDrawString(this.Font, SystemColors.HighlightText);
Gdi.PrepDrawString(this.NormalFont, SystemColors.HighlightText);
rePrep = true;
}
@ -774,7 +795,7 @@ namespace BizHawk.Client.EmuHawk
if (rePrep)
{
Gdi.PrepDrawString(this.Font, this.ForeColor);
Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
}
}
}
@ -785,7 +806,7 @@ namespace BizHawk.Client.EmuHawk
int startRow = FirstVisibleRow;
int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1;
Gdi.PrepDrawString(this.Font, this.ForeColor);
Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
int xPadding = CellWidthPadding + 1 - HBar.Value;
for (int i = 0; i < range; i++) // Vertical
{
@ -817,7 +838,7 @@ namespace BizHawk.Client.EmuHawk
bool rePrep = false;
if (SelectedItems.Contains(new Cell { Column = columns[j], RowIndex = i + startRow }))
{
Gdi.PrepDrawString(this.Font, SystemColors.HighlightText);
Gdi.PrepDrawString(this.NormalFont, SystemColors.HighlightText);
rePrep = true;
}
@ -828,7 +849,7 @@ namespace BizHawk.Client.EmuHawk
if (rePrep)
{
Gdi.PrepDrawString(this.Font, this.ForeColor);
Gdi.PrepDrawString(this.NormalFont, this.ForeColor);
}
}
}