mirror of https://github.com/buggins/dlangui.git
project refactoring - win32 platform support
This commit is contained in:
parent
81833a6db6
commit
3d2fc6df46
Binary file not shown.
Binary file not shown.
|
@ -191,9 +191,6 @@
|
||||||
<Folder name="dlangui">
|
<Folder name="dlangui">
|
||||||
<Folder name="3rdparty">
|
<Folder name="3rdparty">
|
||||||
<Folder name="libpng">
|
<Folder name="libpng">
|
||||||
<Folder name="libs">
|
|
||||||
<File path="3rdparty\libpng\lib\libpng15.lib" />
|
|
||||||
</Folder>
|
|
||||||
<File path="3rdparty\libpng\source\libpng\png.d" />
|
<File path="3rdparty\libpng\source\libpng\png.d" />
|
||||||
<File path="3rdparty\libpng\source\libpng\pngconf.d" />
|
<File path="3rdparty\libpng\source\libpng\pngconf.d" />
|
||||||
<File path="3rdparty\libpng\source\libpng\pnglibconf.d" />
|
<File path="3rdparty\libpng\source\libpng\pnglibconf.d" />
|
||||||
|
@ -266,6 +263,8 @@
|
||||||
<File path="src\dlangui\platforms\common\platform.d" />
|
<File path="src\dlangui\platforms\common\platform.d" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder name="windows">
|
<Folder name="windows">
|
||||||
|
<File path="src\dlangui\platforms\windows\win32drawbuf.d" />
|
||||||
|
<File path="src\dlangui\platforms\windows\win32fonts.d" />
|
||||||
<File path="src\dlangui\platforms\windows\winapp.d" />
|
<File path="src\dlangui\platforms\windows\winapp.d" />
|
||||||
</Folder>
|
</Folder>
|
||||||
</Folder>
|
</Folder>
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
module dlangui.platforms.windows.win32drawbuf;
|
||||||
|
|
||||||
|
version (Windows) {
|
||||||
|
|
||||||
|
import win32.windows;
|
||||||
|
import dlangui.graphics.drawbuf;
|
||||||
|
|
||||||
|
class Win32ColorDrawBuf : ColorDrawBufBase {
|
||||||
|
uint * _pixels;
|
||||||
|
HDC _drawdc;
|
||||||
|
HBITMAP _drawbmp;
|
||||||
|
@property HDC dc() { return _drawdc; }
|
||||||
|
this(int width, int height) {
|
||||||
|
resize(width, height);
|
||||||
|
}
|
||||||
|
override uint * scanLine(int y) {
|
||||||
|
if (y >= 0 && y < _dy)
|
||||||
|
return _pixels + _dx * (_dy - 1 - y);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
override void clear() {
|
||||||
|
if (_drawbmp !is null) {
|
||||||
|
DeleteObject( _drawbmp );
|
||||||
|
DeleteObject( _drawdc );
|
||||||
|
_pixels = null;
|
||||||
|
_dx = 0;
|
||||||
|
_dy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override void resize(int width, int height) {
|
||||||
|
if (width< 0)
|
||||||
|
width = 0;
|
||||||
|
if (height < 0)
|
||||||
|
height = 0;
|
||||||
|
if (_dx == width && _dy == height)
|
||||||
|
return;
|
||||||
|
clear();
|
||||||
|
_dx = width;
|
||||||
|
_dy = height;
|
||||||
|
if (_dx > 0 && _dy > 0) {
|
||||||
|
BITMAPINFO bmi;
|
||||||
|
//memset( &bmi, 0, sizeof(bmi) );
|
||||||
|
bmi.bmiHeader.biSize = (bmi.bmiHeader.sizeof);
|
||||||
|
bmi.bmiHeader.biWidth = _dx;
|
||||||
|
bmi.bmiHeader.biHeight = _dy;
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = 32;
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
bmi.bmiHeader.biSizeImage = 0;
|
||||||
|
bmi.bmiHeader.biXPelsPerMeter = 1024;
|
||||||
|
bmi.bmiHeader.biYPelsPerMeter = 1024;
|
||||||
|
bmi.bmiHeader.biClrUsed = 0;
|
||||||
|
bmi.bmiHeader.biClrImportant = 0;
|
||||||
|
_drawbmp = CreateDIBSection( NULL, &bmi, DIB_RGB_COLORS, cast(void**)(&_pixels), NULL, 0 );
|
||||||
|
_drawdc = CreateCompatibleDC(NULL);
|
||||||
|
SelectObject(_drawdc, _drawbmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override void fill(uint color) {
|
||||||
|
int len = _dx * _dy;
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
_pixels[i] = color;
|
||||||
|
}
|
||||||
|
void drawTo(HDC dc, int x, int y) {
|
||||||
|
BitBlt(dc, x, y, _dx, _dx, _drawdc, 0, 0, SRCCOPY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,479 @@
|
||||||
|
module dlangui.platforms.windows.win32fonts;
|
||||||
|
|
||||||
|
version (Windows) {
|
||||||
|
|
||||||
|
import win32.windows;
|
||||||
|
import dlangui.graphics.fonts;
|
||||||
|
import dlangui.platforms.windows.win32drawbuf;
|
||||||
|
import std.string;
|
||||||
|
import std.utf;
|
||||||
|
|
||||||
|
//auto toUTF16z(S)(S s)
|
||||||
|
//{
|
||||||
|
//return toUTFz!(const(wchar)*)(s);
|
||||||
|
//}
|
||||||
|
|
||||||
|
struct FontDef {
|
||||||
|
immutable FontFamily _family;
|
||||||
|
immutable string _face;
|
||||||
|
immutable ubyte _pitchAndFamily;
|
||||||
|
@property FontFamily family() { return _family; }
|
||||||
|
@property string face() { return _face; }
|
||||||
|
@property ubyte pitchAndFamily() { return _pitchAndFamily; }
|
||||||
|
this(FontFamily family, string face, ubyte putchAndFamily) {
|
||||||
|
_family = family;
|
||||||
|
_face = face;
|
||||||
|
_pitchAndFamily = pitchAndFamily;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Font implementation based on Win32 API system fonts.
|
||||||
|
*/
|
||||||
|
class Win32Font : Font {
|
||||||
|
HFONT _hfont;
|
||||||
|
int _size;
|
||||||
|
int _height;
|
||||||
|
int _weight;
|
||||||
|
int _baseline;
|
||||||
|
bool _italic;
|
||||||
|
string _face;
|
||||||
|
FontFamily _family;
|
||||||
|
LOGFONTA _logfont;
|
||||||
|
Win32ColorDrawBuf _drawbuf;
|
||||||
|
GlyphCache _glyphCache;
|
||||||
|
|
||||||
|
/// need to call create() after construction to initialize font
|
||||||
|
this() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// do cleanup
|
||||||
|
~this() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// cleanup resources
|
||||||
|
override void clear() {
|
||||||
|
if (_hfont !is null)
|
||||||
|
{
|
||||||
|
DeleteObject(_hfont);
|
||||||
|
_hfont = NULL;
|
||||||
|
_height = 0;
|
||||||
|
_baseline = 0;
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
if (_drawbuf !is null) {
|
||||||
|
destroy(_drawbuf);
|
||||||
|
_drawbuf = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getGlyphIndex(dchar code)
|
||||||
|
{
|
||||||
|
if (_drawbuf is null)
|
||||||
|
return 0;
|
||||||
|
wchar[2] s;
|
||||||
|
wchar[2] g;
|
||||||
|
s[0] = cast(wchar)code;
|
||||||
|
s[1] = 0;
|
||||||
|
g[0] = 0;
|
||||||
|
GCP_RESULTSW gcp;
|
||||||
|
gcp.lStructSize = GCP_RESULTSW.sizeof;
|
||||||
|
gcp.lpOutString = null;
|
||||||
|
gcp.lpOrder = null;
|
||||||
|
gcp.lpDx = null;
|
||||||
|
gcp.lpCaretPos = null;
|
||||||
|
gcp.lpClass = null;
|
||||||
|
gcp.lpGlyphs = g.ptr;
|
||||||
|
gcp.nGlyphs = 2;
|
||||||
|
gcp.nMaxFit = 2;
|
||||||
|
|
||||||
|
DWORD res = GetCharacterPlacementW(
|
||||||
|
_drawbuf.dc, s.ptr, 1,
|
||||||
|
1000,
|
||||||
|
&gcp,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (!res)
|
||||||
|
return 0;
|
||||||
|
return g[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
override Glyph * getCharGlyph(dchar ch) {
|
||||||
|
uint glyphIndex = getGlyphIndex(ch);
|
||||||
|
if (!glyphIndex)
|
||||||
|
return null;
|
||||||
|
if (glyphIndex >= 0xFFFF)
|
||||||
|
return null;
|
||||||
|
Glyph * found = _glyphCache.find(cast(ushort)glyphIndex);
|
||||||
|
if (found !is null)
|
||||||
|
return found;
|
||||||
|
GLYPHMETRICS metrics;
|
||||||
|
|
||||||
|
MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
|
||||||
|
uint res;
|
||||||
|
res = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
|
||||||
|
GGO_METRICS,
|
||||||
|
&metrics,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
&identity );
|
||||||
|
if (res==GDI_ERROR)
|
||||||
|
return null;
|
||||||
|
int gs = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
|
||||||
|
GGO_GRAY8_BITMAP, //GGO_METRICS
|
||||||
|
&metrics,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&identity );
|
||||||
|
if (gs >= 0x10000 || gs < 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Glyph g;
|
||||||
|
g.blackBoxX = cast(ubyte)metrics.gmBlackBoxX;
|
||||||
|
g.blackBoxY = cast(ubyte)metrics.gmBlackBoxY;
|
||||||
|
g.originX = cast(byte)metrics.gmptGlyphOrigin.x;
|
||||||
|
g.originY = cast(byte)metrics.gmptGlyphOrigin.y;
|
||||||
|
g.width = cast(ubyte)metrics.gmCellIncX;
|
||||||
|
g.glyphIndex = cast(ushort)glyphIndex;
|
||||||
|
|
||||||
|
if (g.blackBoxX>0 && g.blackBoxY>0)
|
||||||
|
{
|
||||||
|
g.glyph = new ubyte[g.blackBoxX * g.blackBoxY];
|
||||||
|
if (gs>0)
|
||||||
|
{
|
||||||
|
ubyte glyph[] = new ubyte[gs];
|
||||||
|
res = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
|
||||||
|
GGO_GRAY8_BITMAP, //GGO_METRICS
|
||||||
|
&metrics,
|
||||||
|
gs,
|
||||||
|
glyph.ptr,
|
||||||
|
&identity );
|
||||||
|
if (res==GDI_ERROR)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int glyph_row_size = (g.blackBoxX + 3) / 4 * 4;
|
||||||
|
ubyte * src = glyph.ptr;
|
||||||
|
ubyte * dst = g.glyph.ptr;
|
||||||
|
for (int y = 0; y < g.blackBoxY; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < g.blackBoxX; x++)
|
||||||
|
{
|
||||||
|
ubyte b = src[x];
|
||||||
|
if (b>=64)
|
||||||
|
b = 63;
|
||||||
|
b = (b<<2) & 0xFC;
|
||||||
|
dst[x] = b;
|
||||||
|
}
|
||||||
|
src += glyph_row_size;
|
||||||
|
dst += g.blackBoxX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// empty glyph
|
||||||
|
for (int i = g.blackBoxX * g.blackBoxY - 1; i >= 0; i--)
|
||||||
|
g.glyph[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// found!
|
||||||
|
return _glyphCache.put(cast(ushort)glyphIndex, &g);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw text string to buffer
|
||||||
|
override void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color) {
|
||||||
|
int[] widths;
|
||||||
|
int charsMeasured = measureText(text, widths, 3000);
|
||||||
|
for (int i = 0; i < charsMeasured; i++) {
|
||||||
|
int xx = (i > 0) ? widths[i - 1] : 0;
|
||||||
|
Glyph * glyph = getCharGlyph(text[i]);
|
||||||
|
if (glyph is null)
|
||||||
|
continue;
|
||||||
|
if ( glyph.blackBoxX && glyph.blackBoxY ) {
|
||||||
|
buf.drawGlyph( x + xx + glyph.originX,
|
||||||
|
y + _baseline - glyph.originY,
|
||||||
|
glyph.glyph,
|
||||||
|
glyph.blackBoxX,
|
||||||
|
glyph.blackBoxY,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override int measureText(const dchar[] text, ref int[] widths, int maxWidth) {
|
||||||
|
if (_hfont is null || _drawbuf is null || text.length == 0)
|
||||||
|
return 0;
|
||||||
|
wstring utf16text = toUTF16(text);
|
||||||
|
const wchar * pstr = utf16text.ptr;
|
||||||
|
uint len = cast(uint)utf16text.length;
|
||||||
|
GCP_RESULTSW gcpres;
|
||||||
|
gcpres.lStructSize = gcpres.sizeof;
|
||||||
|
if (widths.length < len + 1)
|
||||||
|
widths.length = len + 1;
|
||||||
|
gcpres.lpDx = widths.ptr;
|
||||||
|
gcpres.nMaxFit = len;
|
||||||
|
gcpres.nGlyphs = len;
|
||||||
|
uint res = GetCharacterPlacementW(
|
||||||
|
_drawbuf.dc,
|
||||||
|
pstr,
|
||||||
|
len,
|
||||||
|
maxWidth,
|
||||||
|
&gcpres,
|
||||||
|
GCP_MAXEXTENT); //|GCP_USEKERNING
|
||||||
|
if (!res) {
|
||||||
|
widths[0] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint measured = gcpres.nMaxFit;
|
||||||
|
int total = 0;
|
||||||
|
for (int i = 0; i < measured; i++) {
|
||||||
|
int w = widths[i];
|
||||||
|
total += w;
|
||||||
|
widths[i] = total;
|
||||||
|
}
|
||||||
|
return measured;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create(FontDef * def, int size, int weight, bool italic) {
|
||||||
|
if (!isNull())
|
||||||
|
clear();
|
||||||
|
LOGFONTA lf;
|
||||||
|
lf.lfCharSet = ANSI_CHARSET; //DEFAULT_CHARSET;
|
||||||
|
lf.lfFaceName[0..def.face.length] = def.face;
|
||||||
|
lf.lfFaceName[def.face.length] = 0;
|
||||||
|
lf.lfHeight = -size;
|
||||||
|
lf.lfItalic = italic;
|
||||||
|
lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
|
||||||
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||||
|
lf.lfQuality = ANTIALIASED_QUALITY;
|
||||||
|
lf.lfPitchAndFamily = def.pitchAndFamily;
|
||||||
|
_hfont = CreateFontIndirectA(&lf);
|
||||||
|
_drawbuf = new Win32ColorDrawBuf(1, 1);
|
||||||
|
SelectObject(_drawbuf.dc, _hfont);
|
||||||
|
|
||||||
|
TEXTMETRICW tm;
|
||||||
|
GetTextMetricsW(_drawbuf.dc, &tm);
|
||||||
|
|
||||||
|
_size = size;
|
||||||
|
_height = tm.tmHeight;
|
||||||
|
_baseline = _height - tm.tmDescent;
|
||||||
|
_weight = weight;
|
||||||
|
_italic = italic;
|
||||||
|
_face = def.face;
|
||||||
|
_family = def.family;
|
||||||
|
Log.d("Created font ", _face, " ", _size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear usage flags for all entries
|
||||||
|
override void checkpoint() {
|
||||||
|
_glyphCache.checkpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// removes entries not used after last call of checkpoint() or cleanup()
|
||||||
|
override void cleanup() {
|
||||||
|
_glyphCache.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
@property override int size() { return _size; }
|
||||||
|
@property override int height() { return _height; }
|
||||||
|
@property override int weight() { return _weight; }
|
||||||
|
@property override int baseline() { return _baseline; }
|
||||||
|
@property override bool italic() { return _italic; }
|
||||||
|
@property override string face() { return _face; }
|
||||||
|
@property override FontFamily family() { return _family; }
|
||||||
|
@property override bool isNull() { return _hfont is null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Font manager implementation based on Win32 API system fonts.
|
||||||
|
*/
|
||||||
|
class Win32FontManager : FontManager {
|
||||||
|
FontList _activeFonts;
|
||||||
|
FontDef[] _fontFaces;
|
||||||
|
FontDef*[string] _faceByName;
|
||||||
|
|
||||||
|
/// initialize in constructor
|
||||||
|
this() {
|
||||||
|
instance = this;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// initialize font manager by enumerating of system fonts
|
||||||
|
bool init() {
|
||||||
|
Log.i("Win32FontManager.init()");
|
||||||
|
Win32ColorDrawBuf drawbuf = new Win32ColorDrawBuf(1,1);
|
||||||
|
LOGFONTA lf;
|
||||||
|
lf.lfCharSet = ANSI_CHARSET; //DEFAULT_CHARSET;
|
||||||
|
lf.lfFaceName[0] = 0;
|
||||||
|
HDC dc = drawbuf.dc;
|
||||||
|
int res =
|
||||||
|
EnumFontFamiliesExA(
|
||||||
|
dc, // handle to DC
|
||||||
|
&lf, // font information
|
||||||
|
&LVWin32FontEnumFontFamExProc, // callback function (FONTENUMPROC)
|
||||||
|
cast(LPARAM)(cast(void*)this), // additional data
|
||||||
|
0U // not used; must be 0
|
||||||
|
);
|
||||||
|
destroy(drawbuf);
|
||||||
|
Log.i("Found ", _fontFaces.length, " font faces");
|
||||||
|
return res!=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// for returning of not found font
|
||||||
|
FontRef _emptyFontRef;
|
||||||
|
|
||||||
|
/// get font by properties
|
||||||
|
override ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) {
|
||||||
|
Log.i("getFont()");
|
||||||
|
FontDef * def = findFace(family, face);
|
||||||
|
if (def !is null) {
|
||||||
|
int index = _activeFonts.find(size, weight, italic, def.family, def.face);
|
||||||
|
if (index >= 0)
|
||||||
|
return _activeFonts.get(index);
|
||||||
|
Log.d("Creating new font");
|
||||||
|
Win32Font item = new Win32Font();
|
||||||
|
if (!item.create(def, size, weight, italic))
|
||||||
|
return _emptyFontRef;
|
||||||
|
Log.d("Adding to list of active fonts");
|
||||||
|
return _activeFonts.add(item);
|
||||||
|
} else {
|
||||||
|
return _emptyFontRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// find font face definition by family only (try to get one of defaults for family if possible)
|
||||||
|
FontDef * findFace(FontFamily family) {
|
||||||
|
FontDef * res = null;
|
||||||
|
switch(family) {
|
||||||
|
case FontFamily.SansSerif:
|
||||||
|
res = findFace("Arial"); if (res !is null) return res;
|
||||||
|
res = findFace("Tahoma"); if (res !is null) return res;
|
||||||
|
res = findFace("Calibri"); if (res !is null) return res;
|
||||||
|
res = findFace("Verdana"); if (res !is null) return res;
|
||||||
|
res = findFace("Lucida Sans"); if (res !is null) return res;
|
||||||
|
break;
|
||||||
|
case FontFamily.Serif:
|
||||||
|
res = findFace("Times New Roman"); if (res !is null) return res;
|
||||||
|
res = findFace("Georgia"); if (res !is null) return res;
|
||||||
|
res = findFace("Century Schoolbook"); if (res !is null) return res;
|
||||||
|
res = findFace("Bookman Old Style"); if (res !is null) return res;
|
||||||
|
break;
|
||||||
|
case FontFamily.MonoSpace:
|
||||||
|
res = findFace("Courier New"); if (res !is null) return res;
|
||||||
|
res = findFace("Lucida Console"); if (res !is null) return res;
|
||||||
|
res = findFace("Century Schoolbook"); if (res !is null) return res;
|
||||||
|
res = findFace("Bookman Old Style"); if (res !is null) return res;
|
||||||
|
break;
|
||||||
|
case FontFamily.Cursive:
|
||||||
|
res = findFace("Comic Sans MS"); if (res !is null) return res;
|
||||||
|
res = findFace("Lucida Handwriting"); if (res !is null) return res;
|
||||||
|
res = findFace("Monotype Corsiva"); if (res !is null) return res;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// find font face definition by face only
|
||||||
|
FontDef * findFace(string face) {
|
||||||
|
if (face.length == 0)
|
||||||
|
return null;
|
||||||
|
if (face in _faceByName)
|
||||||
|
return _faceByName[face];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// find font face definition by family and face
|
||||||
|
FontDef * findFace(FontFamily family, string face) {
|
||||||
|
// by face only
|
||||||
|
FontDef * res = findFace(face);
|
||||||
|
if (res !is null)
|
||||||
|
return res;
|
||||||
|
// best for family
|
||||||
|
res = findFace(family);
|
||||||
|
if (res !is null)
|
||||||
|
return res;
|
||||||
|
for (int i = 0; i < _fontFaces.length; i++) {
|
||||||
|
res = &_fontFaces[i];
|
||||||
|
if (res.family == family)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
res = findFace(FontFamily.SansSerif);
|
||||||
|
if (res !is null)
|
||||||
|
return res;
|
||||||
|
return &_fontFaces[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// register enumerated font
|
||||||
|
bool registerFont(FontFamily family, string fontFace, ubyte pitchAndFamily) {
|
||||||
|
Log.d("registerFont(", family, ",", fontFace, ")");
|
||||||
|
_fontFaces ~= FontDef(family, fontFace, pitchAndFamily);
|
||||||
|
_faceByName[fontFace] = &_fontFaces[$ - 1];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// clear usage flags for all entries
|
||||||
|
override void checkpoint() {
|
||||||
|
_activeFonts.checkpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// removes entries not used after last call of checkpoint() or cleanup()
|
||||||
|
override void cleanup() {
|
||||||
|
_activeFonts.cleanup();
|
||||||
|
//_list.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string fromStringz(const(char[]) s) {
|
||||||
|
int i = 0;
|
||||||
|
while(s[i])
|
||||||
|
i++;
|
||||||
|
return cast(string)(s[0..i].dup);
|
||||||
|
}
|
||||||
|
|
||||||
|
FontFamily pitchAndFamilyToFontFamily(ubyte flags) {
|
||||||
|
if ((flags & FF_DECORATIVE) == FF_DECORATIVE)
|
||||||
|
return FontFamily.Fantasy;
|
||||||
|
else if ((flags & (FIXED_PITCH)) != 0) // | | MONO_FONT
|
||||||
|
return FontFamily.MonoSpace;
|
||||||
|
else if ((flags & (FF_ROMAN)) != 0)
|
||||||
|
return FontFamily.Serif;
|
||||||
|
else if ((flags & (FF_SCRIPT)) != 0)
|
||||||
|
return FontFamily.Cursive;
|
||||||
|
return FontFamily.SansSerif;
|
||||||
|
}
|
||||||
|
|
||||||
|
// definition
|
||||||
|
extern(Windows) {
|
||||||
|
int LVWin32FontEnumFontFamExProc(
|
||||||
|
const (LOGFONTA) *lf, // logical-font data
|
||||||
|
const (TEXTMETRICA) *lpntme, // physical-font data
|
||||||
|
//ENUMLOGFONTEX *lpelfe, // logical-font data
|
||||||
|
//NEWTEXTMETRICEX *lpntme, // physical-font data
|
||||||
|
DWORD fontType, // type of font
|
||||||
|
LPARAM lParam // application-defined data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
//Log.d("LVWin32FontEnumFontFamExProc fontType=", fontType);
|
||||||
|
if (fontType == TRUETYPE_FONTTYPE)
|
||||||
|
{
|
||||||
|
void * p = cast(void*)lParam;
|
||||||
|
Win32FontManager fontman = cast(Win32FontManager)p;
|
||||||
|
string face = fromStringz(lf.lfFaceName);
|
||||||
|
FontFamily family = pitchAndFamilyToFontFamily(lf.lfPitchAndFamily);
|
||||||
|
if (face.length < 2 || face[0] == '@')
|
||||||
|
return 1;
|
||||||
|
//Log.d("face:", face);
|
||||||
|
fontman.registerFont(family, face, lf.lfPitchAndFamily);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ import std.utf;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
import dlangui.platforms.common.platform;
|
import dlangui.platforms.common.platform;
|
||||||
|
import dlangui.platforms.windows.win32fonts;
|
||||||
|
import dlangui.platforms.windows.win32drawbuf;
|
||||||
import dlangui.graphics.drawbuf;
|
import dlangui.graphics.drawbuf;
|
||||||
import dlangui.graphics.fonts;
|
import dlangui.graphics.fonts;
|
||||||
import dlangui.core.logger;
|
import dlangui.core.logger;
|
||||||
|
@ -17,468 +19,6 @@ pragma(lib, "gdi32.lib");
|
||||||
pragma(lib, "user32.lib");
|
pragma(lib, "user32.lib");
|
||||||
pragma(lib, "libpng15.lib");
|
pragma(lib, "libpng15.lib");
|
||||||
|
|
||||||
struct FontDef {
|
|
||||||
immutable FontFamily _family;
|
|
||||||
immutable string _face;
|
|
||||||
immutable ubyte _pitchAndFamily;
|
|
||||||
@property FontFamily family() { return _family; }
|
|
||||||
@property string face() { return _face; }
|
|
||||||
@property ubyte pitchAndFamily() { return _pitchAndFamily; }
|
|
||||||
this(FontFamily family, string face, ubyte putchAndFamily) {
|
|
||||||
_family = family;
|
|
||||||
_face = face;
|
|
||||||
_pitchAndFamily = pitchAndFamily;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Font implementation based on Win32 API system fonts.
|
|
||||||
*/
|
|
||||||
class Win32Font : Font {
|
|
||||||
HFONT _hfont;
|
|
||||||
int _size;
|
|
||||||
int _height;
|
|
||||||
int _weight;
|
|
||||||
int _baseline;
|
|
||||||
bool _italic;
|
|
||||||
string _face;
|
|
||||||
FontFamily _family;
|
|
||||||
LOGFONTA _logfont;
|
|
||||||
Win32ColorDrawBuf _drawbuf;
|
|
||||||
GlyphCache _glyphCache;
|
|
||||||
|
|
||||||
/// need to call create() after construction to initialize font
|
|
||||||
this() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// do cleanup
|
|
||||||
~this() {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// cleanup resources
|
|
||||||
override void clear() {
|
|
||||||
if (_hfont !is null)
|
|
||||||
{
|
|
||||||
DeleteObject(_hfont);
|
|
||||||
_hfont = NULL;
|
|
||||||
_height = 0;
|
|
||||||
_baseline = 0;
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
if (_drawbuf !is null) {
|
|
||||||
destroy(_drawbuf);
|
|
||||||
_drawbuf = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint getGlyphIndex(dchar code)
|
|
||||||
{
|
|
||||||
if (_drawbuf is null)
|
|
||||||
return 0;
|
|
||||||
wchar[2] s;
|
|
||||||
wchar[2] g;
|
|
||||||
s[0] = cast(wchar)code;
|
|
||||||
s[1] = 0;
|
|
||||||
g[0] = 0;
|
|
||||||
GCP_RESULTSW gcp;
|
|
||||||
gcp.lStructSize = GCP_RESULTSW.sizeof;
|
|
||||||
gcp.lpOutString = null;
|
|
||||||
gcp.lpOrder = null;
|
|
||||||
gcp.lpDx = null;
|
|
||||||
gcp.lpCaretPos = null;
|
|
||||||
gcp.lpClass = null;
|
|
||||||
gcp.lpGlyphs = g.ptr;
|
|
||||||
gcp.nGlyphs = 2;
|
|
||||||
gcp.nMaxFit = 2;
|
|
||||||
|
|
||||||
DWORD res = GetCharacterPlacementW(
|
|
||||||
_drawbuf.dc, s.ptr, 1,
|
|
||||||
1000,
|
|
||||||
&gcp,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
if (!res)
|
|
||||||
return 0;
|
|
||||||
return g[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
override Glyph * getCharGlyph(dchar ch) {
|
|
||||||
uint glyphIndex = getGlyphIndex(ch);
|
|
||||||
if (!glyphIndex)
|
|
||||||
return null;
|
|
||||||
if (glyphIndex >= 0xFFFF)
|
|
||||||
return null;
|
|
||||||
Glyph * found = _glyphCache.find(cast(ushort)glyphIndex);
|
|
||||||
if (found !is null)
|
|
||||||
return found;
|
|
||||||
GLYPHMETRICS metrics;
|
|
||||||
|
|
||||||
MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
|
|
||||||
uint res;
|
|
||||||
res = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
|
|
||||||
GGO_METRICS,
|
|
||||||
&metrics,
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
&identity );
|
|
||||||
if (res==GDI_ERROR)
|
|
||||||
return null;
|
|
||||||
int gs = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
|
|
||||||
GGO_GRAY8_BITMAP, //GGO_METRICS
|
|
||||||
&metrics,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&identity );
|
|
||||||
if (gs >= 0x10000 || gs < 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Glyph g;
|
|
||||||
g.blackBoxX = cast(ubyte)metrics.gmBlackBoxX;
|
|
||||||
g.blackBoxY = cast(ubyte)metrics.gmBlackBoxY;
|
|
||||||
g.originX = cast(byte)metrics.gmptGlyphOrigin.x;
|
|
||||||
g.originY = cast(byte)metrics.gmptGlyphOrigin.y;
|
|
||||||
g.width = cast(ubyte)metrics.gmCellIncX;
|
|
||||||
g.glyphIndex = cast(ushort)glyphIndex;
|
|
||||||
|
|
||||||
if (g.blackBoxX>0 && g.blackBoxY>0)
|
|
||||||
{
|
|
||||||
g.glyph = new ubyte[g.blackBoxX * g.blackBoxY];
|
|
||||||
if (gs>0)
|
|
||||||
{
|
|
||||||
ubyte glyph[] = new ubyte[gs];
|
|
||||||
res = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
|
|
||||||
GGO_GRAY8_BITMAP, //GGO_METRICS
|
|
||||||
&metrics,
|
|
||||||
gs,
|
|
||||||
glyph.ptr,
|
|
||||||
&identity );
|
|
||||||
if (res==GDI_ERROR)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int glyph_row_size = (g.blackBoxX + 3) / 4 * 4;
|
|
||||||
ubyte * src = glyph.ptr;
|
|
||||||
ubyte * dst = g.glyph.ptr;
|
|
||||||
for (int y = 0; y < g.blackBoxY; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < g.blackBoxX; x++)
|
|
||||||
{
|
|
||||||
ubyte b = src[x];
|
|
||||||
if (b>=64)
|
|
||||||
b = 63;
|
|
||||||
b = (b<<2) & 0xFC;
|
|
||||||
dst[x] = b;
|
|
||||||
}
|
|
||||||
src += glyph_row_size;
|
|
||||||
dst += g.blackBoxX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// empty glyph
|
|
||||||
for (int i = g.blackBoxX * g.blackBoxY - 1; i >= 0; i--)
|
|
||||||
g.glyph[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// found!
|
|
||||||
return _glyphCache.put(cast(ushort)glyphIndex, &g);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw text string to buffer
|
|
||||||
override void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color) {
|
|
||||||
int[] widths;
|
|
||||||
int charsMeasured = measureText(text, widths, 3000);
|
|
||||||
for (int i = 0; i < charsMeasured; i++) {
|
|
||||||
int xx = (i > 0) ? widths[i - 1] : 0;
|
|
||||||
Glyph * glyph = getCharGlyph(text[i]);
|
|
||||||
if (glyph is null)
|
|
||||||
continue;
|
|
||||||
if ( glyph.blackBoxX && glyph.blackBoxY ) {
|
|
||||||
buf.drawGlyph( x + xx + glyph.originX,
|
|
||||||
y + _baseline - glyph.originY,
|
|
||||||
glyph.glyph,
|
|
||||||
glyph.blackBoxX,
|
|
||||||
glyph.blackBoxY,
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override int measureText(const dchar[] text, ref int[] widths, int maxWidth) {
|
|
||||||
if (_hfont is null || _drawbuf is null || text.length == 0)
|
|
||||||
return 0;
|
|
||||||
wstring utf16text = toUTF16(text);
|
|
||||||
const wchar * pstr = utf16text.ptr;
|
|
||||||
uint len = cast(uint)utf16text.length;
|
|
||||||
GCP_RESULTSW gcpres;
|
|
||||||
gcpres.lStructSize = gcpres.sizeof;
|
|
||||||
if (widths.length < len + 1)
|
|
||||||
widths.length = len + 1;
|
|
||||||
gcpres.lpDx = widths.ptr;
|
|
||||||
gcpres.nMaxFit = len;
|
|
||||||
gcpres.nGlyphs = len;
|
|
||||||
uint res = GetCharacterPlacementW(
|
|
||||||
_drawbuf.dc,
|
|
||||||
pstr,
|
|
||||||
len,
|
|
||||||
maxWidth,
|
|
||||||
&gcpres,
|
|
||||||
GCP_MAXEXTENT); //|GCP_USEKERNING
|
|
||||||
if (!res) {
|
|
||||||
widths[0] = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint measured = gcpres.nMaxFit;
|
|
||||||
int total = 0;
|
|
||||||
for (int i = 0; i < measured; i++) {
|
|
||||||
int w = widths[i];
|
|
||||||
total += w;
|
|
||||||
widths[i] = total;
|
|
||||||
}
|
|
||||||
return measured;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool create(FontDef * def, int size, int weight, bool italic) {
|
|
||||||
if (!isNull())
|
|
||||||
clear();
|
|
||||||
LOGFONTA lf;
|
|
||||||
lf.lfCharSet = ANSI_CHARSET; //DEFAULT_CHARSET;
|
|
||||||
lf.lfFaceName[0..def.face.length] = def.face;
|
|
||||||
lf.lfFaceName[def.face.length] = 0;
|
|
||||||
lf.lfHeight = -size;
|
|
||||||
lf.lfItalic = italic;
|
|
||||||
lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
|
|
||||||
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
||||||
lf.lfQuality = ANTIALIASED_QUALITY;
|
|
||||||
lf.lfPitchAndFamily = def.pitchAndFamily;
|
|
||||||
_hfont = CreateFontIndirectA(&lf);
|
|
||||||
_drawbuf = new Win32ColorDrawBuf(1, 1);
|
|
||||||
SelectObject(_drawbuf.dc, _hfont);
|
|
||||||
|
|
||||||
TEXTMETRICW tm;
|
|
||||||
GetTextMetricsW(_drawbuf.dc, &tm);
|
|
||||||
|
|
||||||
_size = size;
|
|
||||||
_height = tm.tmHeight;
|
|
||||||
_baseline = _height - tm.tmDescent;
|
|
||||||
_weight = weight;
|
|
||||||
_italic = italic;
|
|
||||||
_face = def.face;
|
|
||||||
_family = def.family;
|
|
||||||
Log.d("Created font ", _face, " ", _size);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear usage flags for all entries
|
|
||||||
override void checkpoint() {
|
|
||||||
_glyphCache.checkpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// removes entries not used after last call of checkpoint() or cleanup()
|
|
||||||
override void cleanup() {
|
|
||||||
_glyphCache.cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@property override int size() { return _size; }
|
|
||||||
@property override int height() { return _height; }
|
|
||||||
@property override int weight() { return _weight; }
|
|
||||||
@property override int baseline() { return _baseline; }
|
|
||||||
@property override bool italic() { return _italic; }
|
|
||||||
@property override string face() { return _face; }
|
|
||||||
@property override FontFamily family() { return _family; }
|
|
||||||
@property override bool isNull() { return _hfont is null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Font manager implementation based on Win32 API system fonts.
|
|
||||||
*/
|
|
||||||
class Win32FontManager : FontManager {
|
|
||||||
FontList _activeFonts;
|
|
||||||
FontDef[] _fontFaces;
|
|
||||||
FontDef*[string] _faceByName;
|
|
||||||
|
|
||||||
/// initialize in constructor
|
|
||||||
this() {
|
|
||||||
instance = this;
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// initialize font manager by enumerating of system fonts
|
|
||||||
bool init() {
|
|
||||||
Log.i("Win32FontManager.init()");
|
|
||||||
Win32ColorDrawBuf drawbuf = new Win32ColorDrawBuf(1,1);
|
|
||||||
LOGFONTA lf;
|
|
||||||
lf.lfCharSet = ANSI_CHARSET; //DEFAULT_CHARSET;
|
|
||||||
lf.lfFaceName[0] = 0;
|
|
||||||
HDC dc = drawbuf.dc;
|
|
||||||
int res =
|
|
||||||
EnumFontFamiliesExA(
|
|
||||||
dc, // handle to DC
|
|
||||||
&lf, // font information
|
|
||||||
&LVWin32FontEnumFontFamExProc, // callback function (FONTENUMPROC)
|
|
||||||
cast(LPARAM)(cast(void*)this), // additional data
|
|
||||||
0U // not used; must be 0
|
|
||||||
);
|
|
||||||
destroy(drawbuf);
|
|
||||||
Log.i("Found ", _fontFaces.length, " font faces");
|
|
||||||
return res!=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// for returning of not found font
|
|
||||||
FontRef _emptyFontRef;
|
|
||||||
|
|
||||||
/// get font by properties
|
|
||||||
override ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) {
|
|
||||||
Log.i("getFont()");
|
|
||||||
FontDef * def = findFace(family, face);
|
|
||||||
if (def !is null) {
|
|
||||||
int index = _activeFonts.find(size, weight, italic, def.family, def.face);
|
|
||||||
if (index >= 0)
|
|
||||||
return _activeFonts.get(index);
|
|
||||||
Log.d("Creating new font");
|
|
||||||
Win32Font item = new Win32Font();
|
|
||||||
if (!item.create(def, size, weight, italic))
|
|
||||||
return _emptyFontRef;
|
|
||||||
Log.d("Adding to list of active fonts");
|
|
||||||
return _activeFonts.add(item);
|
|
||||||
} else {
|
|
||||||
return _emptyFontRef;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// find font face definition by family only (try to get one of defaults for family if possible)
|
|
||||||
FontDef * findFace(FontFamily family) {
|
|
||||||
FontDef * res = null;
|
|
||||||
switch(family) {
|
|
||||||
case FontFamily.SansSerif:
|
|
||||||
res = findFace("Arial"); if (res !is null) return res;
|
|
||||||
res = findFace("Tahoma"); if (res !is null) return res;
|
|
||||||
res = findFace("Calibri"); if (res !is null) return res;
|
|
||||||
res = findFace("Verdana"); if (res !is null) return res;
|
|
||||||
res = findFace("Lucida Sans"); if (res !is null) return res;
|
|
||||||
break;
|
|
||||||
case FontFamily.Serif:
|
|
||||||
res = findFace("Times New Roman"); if (res !is null) return res;
|
|
||||||
res = findFace("Georgia"); if (res !is null) return res;
|
|
||||||
res = findFace("Century Schoolbook"); if (res !is null) return res;
|
|
||||||
res = findFace("Bookman Old Style"); if (res !is null) return res;
|
|
||||||
break;
|
|
||||||
case FontFamily.MonoSpace:
|
|
||||||
res = findFace("Courier New"); if (res !is null) return res;
|
|
||||||
res = findFace("Lucida Console"); if (res !is null) return res;
|
|
||||||
res = findFace("Century Schoolbook"); if (res !is null) return res;
|
|
||||||
res = findFace("Bookman Old Style"); if (res !is null) return res;
|
|
||||||
break;
|
|
||||||
case FontFamily.Cursive:
|
|
||||||
res = findFace("Comic Sans MS"); if (res !is null) return res;
|
|
||||||
res = findFace("Lucida Handwriting"); if (res !is null) return res;
|
|
||||||
res = findFace("Monotype Corsiva"); if (res !is null) return res;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// find font face definition by face only
|
|
||||||
FontDef * findFace(string face) {
|
|
||||||
if (face.length == 0)
|
|
||||||
return null;
|
|
||||||
if (face in _faceByName)
|
|
||||||
return _faceByName[face];
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// find font face definition by family and face
|
|
||||||
FontDef * findFace(FontFamily family, string face) {
|
|
||||||
// by face only
|
|
||||||
FontDef * res = findFace(face);
|
|
||||||
if (res !is null)
|
|
||||||
return res;
|
|
||||||
// best for family
|
|
||||||
res = findFace(family);
|
|
||||||
if (res !is null)
|
|
||||||
return res;
|
|
||||||
for (int i = 0; i < _fontFaces.length; i++) {
|
|
||||||
res = &_fontFaces[i];
|
|
||||||
if (res.family == family)
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
res = findFace(FontFamily.SansSerif);
|
|
||||||
if (res !is null)
|
|
||||||
return res;
|
|
||||||
return &_fontFaces[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// register enumerated font
|
|
||||||
bool registerFont(FontFamily family, string fontFace, ubyte pitchAndFamily) {
|
|
||||||
Log.d("registerFont(", family, ",", fontFace, ")");
|
|
||||||
_fontFaces ~= FontDef(family, fontFace, pitchAndFamily);
|
|
||||||
_faceByName[fontFace] = &_fontFaces[$ - 1];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// clear usage flags for all entries
|
|
||||||
override void checkpoint() {
|
|
||||||
_activeFonts.checkpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// removes entries not used after last call of checkpoint() or cleanup()
|
|
||||||
override void cleanup() {
|
|
||||||
_activeFonts.cleanup();
|
|
||||||
//_list.cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string fromStringz(const(char[]) s) {
|
|
||||||
int i = 0;
|
|
||||||
while(s[i])
|
|
||||||
i++;
|
|
||||||
return cast(string)(s[0..i].dup);
|
|
||||||
}
|
|
||||||
|
|
||||||
FontFamily pitchAndFamilyToFontFamily(ubyte flags) {
|
|
||||||
if ((flags & FF_DECORATIVE) == FF_DECORATIVE)
|
|
||||||
return FontFamily.Fantasy;
|
|
||||||
else if ((flags & (FIXED_PITCH)) != 0) // | | MONO_FONT
|
|
||||||
return FontFamily.MonoSpace;
|
|
||||||
else if ((flags & (FF_ROMAN)) != 0)
|
|
||||||
return FontFamily.Serif;
|
|
||||||
else if ((flags & (FF_SCRIPT)) != 0)
|
|
||||||
return FontFamily.Cursive;
|
|
||||||
return FontFamily.SansSerif;
|
|
||||||
}
|
|
||||||
|
|
||||||
// definition
|
|
||||||
extern(Windows) {
|
|
||||||
int LVWin32FontEnumFontFamExProc(
|
|
||||||
const (LOGFONTA) *lf, // logical-font data
|
|
||||||
const (TEXTMETRICA) *lpntme, // physical-font data
|
|
||||||
//ENUMLOGFONTEX *lpelfe, // logical-font data
|
|
||||||
//NEWTEXTMETRICEX *lpntme, // physical-font data
|
|
||||||
DWORD fontType, // type of font
|
|
||||||
LPARAM lParam // application-defined data
|
|
||||||
)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
//Log.d("LVWin32FontEnumFontFamExProc fontType=", fontType);
|
|
||||||
if (fontType == TRUETYPE_FONTTYPE)
|
|
||||||
{
|
|
||||||
void * p = cast(void*)lParam;
|
|
||||||
Win32FontManager fontman = cast(Win32FontManager)p;
|
|
||||||
string face = fromStringz(lf.lfFaceName);
|
|
||||||
FontFamily family = pitchAndFamilyToFontFamily(lf.lfPitchAndFamily);
|
|
||||||
if (face.length < 2 || face[0] == '@')
|
|
||||||
return 1;
|
|
||||||
//Log.d("face:", face);
|
|
||||||
fontman.registerFont(family, face, lf.lfPitchAndFamily);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern (C) int UIAppMain();
|
extern (C) int UIAppMain();
|
||||||
|
|
||||||
immutable WIN_CLASS_NAME = "DLANGUI_APP";
|
immutable WIN_CLASS_NAME = "DLANGUI_APP";
|
||||||
|
@ -572,11 +112,6 @@ class Win32Platform : Platform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto toUTF16z(S)(S s)
|
|
||||||
{
|
|
||||||
return toUTFz!(const(wchar)*)(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern (Windows)
|
extern (Windows)
|
||||||
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||||
LPSTR lpCmdLine, int nCmdShow)
|
LPSTR lpCmdLine, int nCmdShow)
|
||||||
|
@ -625,103 +160,6 @@ int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
|
||||||
return UIAppMain();
|
return UIAppMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Win32ColorDrawBuf : ColorDrawBufBase {
|
|
||||||
uint * _pixels;
|
|
||||||
HDC _drawdc;
|
|
||||||
HBITMAP _drawbmp;
|
|
||||||
@property HDC dc() { return _drawdc; }
|
|
||||||
this(int width, int height) {
|
|
||||||
resize(width, height);
|
|
||||||
}
|
|
||||||
override uint * scanLine(int y) {
|
|
||||||
if (y >= 0 && y < _dy)
|
|
||||||
return _pixels + _dx * (_dy - 1 - y);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
override void clear() {
|
|
||||||
if (_drawbmp !is null) {
|
|
||||||
DeleteObject( _drawbmp );
|
|
||||||
DeleteObject( _drawdc );
|
|
||||||
_pixels = null;
|
|
||||||
_dx = 0;
|
|
||||||
_dy = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override void resize(int width, int height) {
|
|
||||||
if (width< 0)
|
|
||||||
width = 0;
|
|
||||||
if (height < 0)
|
|
||||||
height = 0;
|
|
||||||
if (_dx == width && _dy == height)
|
|
||||||
return;
|
|
||||||
clear();
|
|
||||||
_dx = width;
|
|
||||||
_dy = height;
|
|
||||||
if (_dx > 0 && _dy > 0) {
|
|
||||||
BITMAPINFO bmi;
|
|
||||||
//memset( &bmi, 0, sizeof(bmi) );
|
|
||||||
bmi.bmiHeader.biSize = (bmi.bmiHeader.sizeof);
|
|
||||||
bmi.bmiHeader.biWidth = _dx;
|
|
||||||
bmi.bmiHeader.biHeight = _dy;
|
|
||||||
bmi.bmiHeader.biPlanes = 1;
|
|
||||||
bmi.bmiHeader.biBitCount = 32;
|
|
||||||
bmi.bmiHeader.biCompression = BI_RGB;
|
|
||||||
bmi.bmiHeader.biSizeImage = 0;
|
|
||||||
bmi.bmiHeader.biXPelsPerMeter = 1024;
|
|
||||||
bmi.bmiHeader.biYPelsPerMeter = 1024;
|
|
||||||
bmi.bmiHeader.biClrUsed = 0;
|
|
||||||
bmi.bmiHeader.biClrImportant = 0;
|
|
||||||
_drawbmp = CreateDIBSection( NULL, &bmi, DIB_RGB_COLORS, cast(void**)(&_pixels), NULL, 0 );
|
|
||||||
_drawdc = CreateCompatibleDC(NULL);
|
|
||||||
SelectObject(_drawdc, _drawbmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override void fill(uint color) {
|
|
||||||
int len = _dx * _dy;
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
_pixels[i] = color;
|
|
||||||
}
|
|
||||||
void drawTo(HDC dc, int x, int y) {
|
|
||||||
BitBlt(dc, x, y, _dx, _dx, _drawdc, 0, 0, SRCCOPY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//void drawBuf2DC(HDC dc, int x, int y, DrawBuf buf)
|
|
||||||
//{
|
|
||||||
// uint * drawpixels;
|
|
||||||
// HDC drawdc;
|
|
||||||
// HBITMAP drawbmp;
|
|
||||||
//
|
|
||||||
// int buf_width = buf.width();
|
|
||||||
// int bytesPerRow = buf_width * 4;
|
|
||||||
// BITMAPINFO bmi;
|
|
||||||
// //memset( &bmi, 0, sizeof(bmi) );
|
|
||||||
// bmi.bmiHeader.biSize = (bmi.bmiHeader.sizeof);
|
|
||||||
// bmi.bmiHeader.biWidth = buf_width;
|
|
||||||
// bmi.bmiHeader.biHeight = buf.height;
|
|
||||||
// bmi.bmiHeader.biPlanes = 1;
|
|
||||||
// bmi.bmiHeader.biBitCount = 32;
|
|
||||||
// bmi.bmiHeader.biCompression = BI_RGB;
|
|
||||||
// bmi.bmiHeader.biSizeImage = 0;
|
|
||||||
// bmi.bmiHeader.biXPelsPerMeter = 1024;
|
|
||||||
// bmi.bmiHeader.biYPelsPerMeter = 1024;
|
|
||||||
// bmi.bmiHeader.biClrUsed = 0;
|
|
||||||
// bmi.bmiHeader.biClrImportant = 0;
|
|
||||||
// drawbmp = CreateDIBSection( NULL, &bmi, DIB_RGB_COLORS, cast(void**)(&drawpixels), NULL, 0 );
|
|
||||||
// drawdc = CreateCompatibleDC(NULL);
|
|
||||||
// SelectObject(drawdc, drawbmp);
|
|
||||||
// for (int yy=0; yy < buf.height; yy++)
|
|
||||||
// {
|
|
||||||
// uint * src = buf.scanLine(yy);
|
|
||||||
// uint * dst = drawpixels + (buf.height - 1 - yy) * buf.width;
|
|
||||||
// for (int xx = 0; xx < buf_width; xx++)
|
|
||||||
// dst[xx] = src[xx];
|
|
||||||
// }
|
|
||||||
// BitBlt( dc, x, y, buf_width, buf.height, drawdc, 0, 0, SRCCOPY);
|
|
||||||
// DeleteObject( drawbmp );
|
|
||||||
// DeleteObject( drawdc );
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
extern(Windows)
|
extern(Windows)
|
||||||
LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
Loading…
Reference in New Issue