mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-27 09:58:45 +01:00
Use new api. Use small for cell and large for tile still, but now
create and cache an actual HBITMAP, and prefer it to letters. This is needed for Catalan where "L-L" will never fit. Still to be done: prefer letters to bitmap where they'll actually fit (devices where tiles drawn wider), and position better in tray. May also want to allow scaling.
This commit is contained in:
parent
5b8c6844a5
commit
140ac0a597
1 changed files with 197 additions and 66 deletions
263
wince/cedraw.c
263
wince/cedraw.c
|
@ -34,6 +34,7 @@
|
|||
#include "cedefines.h"
|
||||
#include "cedebug.h"
|
||||
#include "debhacks.h"
|
||||
#include "strutils.h"
|
||||
|
||||
#ifndef DRAW_FUNC_NAME
|
||||
#define DRAW_FUNC_NAME(nam) ce_draw_ ## nam
|
||||
|
@ -86,6 +87,11 @@ typedef struct _FontCacheEntry {
|
|||
XP_U16 offset;
|
||||
} FontCacheEntry;
|
||||
|
||||
typedef struct _CeBMCacheEntry {
|
||||
XP_UCHAR letters[4]; /* currently the max */
|
||||
HBITMAP bms[2];
|
||||
} CeBMCacheEntry;
|
||||
|
||||
struct CEDrawCtx {
|
||||
DrawCtxVTable* vtable;
|
||||
|
||||
|
@ -102,6 +108,7 @@ struct CEDrawCtx {
|
|||
HGDIOBJ hintPens[MAX_NUM_PLAYERS];
|
||||
|
||||
FontCacheEntry fcEntry[N_RESIZE_FONTS];
|
||||
CeBMCacheEntry bmCache[3]; /* 3: max specials in current use */
|
||||
|
||||
HBITMAP rightArrow;
|
||||
HBITMAP downArrow;
|
||||
|
@ -153,6 +160,14 @@ XPRtoRECT( RECT* rt, const XP_Rect* xprect )
|
|||
rt->bottom = rt->top + xprect->height;
|
||||
} /* XPRtoRECT */
|
||||
|
||||
static void
|
||||
ceDeleteObjectNotNull( HGDIOBJ obj )
|
||||
{
|
||||
if ( !!obj ) {
|
||||
DeleteObject( obj );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DRAW_FOCUS_FRAME
|
||||
static HGDIOBJ
|
||||
ceGetPen( CEDrawCtx* dctx, XP_U16 colorIndx, XP_U16 width )
|
||||
|
@ -425,13 +440,27 @@ ceClearFontCache( CEDrawCtx* dctx )
|
|||
{
|
||||
XP_U16 ii;
|
||||
for ( ii = 0; ii < N_RESIZE_FONTS; ++ii ) {
|
||||
if ( !!dctx->fcEntry[ii].setFont ) {
|
||||
DeleteObject( dctx->fcEntry[ii].setFont );
|
||||
}
|
||||
ceDeleteObjectNotNull( dctx->fcEntry[ii].setFont );
|
||||
}
|
||||
XP_MEMSET( &dctx->fcEntry, 0, sizeof(dctx->fcEntry) );
|
||||
}
|
||||
|
||||
static void
|
||||
ceClearBmCache( CEDrawCtx* dctx )
|
||||
{
|
||||
XP_U16 ii;
|
||||
CeBMCacheEntry* entry;
|
||||
|
||||
for ( entry = dctx->bmCache, ii = 0;
|
||||
ii < VSIZE(dctx->bmCache); ++ii, ++entry ) {
|
||||
ceDeleteObjectNotNull( entry->bms[0] );
|
||||
ceDeleteObjectNotNull( entry->bms[1] );
|
||||
}
|
||||
|
||||
/* clear letters in case we're changing not deleting */
|
||||
XP_MEMSET( &dctx->bmCache[0], 0, sizeof(dctx->bmCache) );
|
||||
} /* ceClearBmCache */
|
||||
|
||||
static void
|
||||
ceFillFontInfo( const CEDrawCtx* dctx, LOGFONT* fontInfo,
|
||||
XP_U16 height/* , XP_Bool bold */ )
|
||||
|
@ -485,9 +514,7 @@ ceBestFitFont( CEDrawCtx* dctx, const XP_U16 soughtHeight,
|
|||
XP_U16 prevHeight = testHeight;
|
||||
LOGFONT fontInfo;
|
||||
|
||||
if ( !!testFont ) {
|
||||
DeleteObject( testFont );
|
||||
}
|
||||
ceDeleteObjectNotNull( testFont );
|
||||
|
||||
ceFillFontInfo( dctx, &fontInfo, testHeight );
|
||||
testFont = CreateFontIndirect( &fontInfo );
|
||||
|
@ -589,6 +616,103 @@ ceGetSizedFont( CEDrawCtx* dctx, XP_U16 height, XP_U16 width, RFIndex index )
|
|||
return fce;
|
||||
} /* ceGetSizedFont */
|
||||
|
||||
static HBITMAP
|
||||
checkBMCache( CEDrawCtx* dctx, HDC hdc, const XP_UCHAR* letters, XP_U16 index,
|
||||
const XP_Bitmaps* bitmaps, XP_Bool* cached )
|
||||
{
|
||||
HBITMAP bm = NULL;
|
||||
CeBMCacheEntry* entry = NULL;
|
||||
XP_U16 len = 1 + XP_STRLEN( letters );
|
||||
XP_Bool canCache = XP_FALSE;
|
||||
|
||||
XP_ASSERT( index < 2 );
|
||||
|
||||
if ( len < sizeof( entry->letters ) ) {
|
||||
XP_U16 ii;
|
||||
for ( ii = 0, entry = dctx->bmCache; ii < VSIZE(dctx->bmCache);
|
||||
++ii, ++entry ) {
|
||||
if ( 0 == entry->letters[0] ) { /* available */
|
||||
XP_MEMCPY( entry->letters, letters, len );
|
||||
canCache = XP_TRUE;
|
||||
break;
|
||||
} else if ( !XP_STRNCMP( entry->letters, letters, len ) ) {
|
||||
canCache = XP_TRUE;
|
||||
bm = entry->bms[index]; /* may be null */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if ( !canCache ) {
|
||||
XP_WARNF( "%s: unable to cache bitmap for %s", __func__, letters );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( !bm ) {
|
||||
const CEBitmapInfo* info = (const CEBitmapInfo*)bitmaps->bmps[index];
|
||||
XP_U16 nCols, nRows, row, col, rowBytes;
|
||||
COLORREF black = dctx->globals->appPrefs.colors[CE_BLACK_COLOR];
|
||||
COLORREF white = dctx->globals->appPrefs.colors[CE_WHITE_COLOR];
|
||||
HDC tmpDC;
|
||||
XP_U8* bits = info->bits;
|
||||
|
||||
nCols = info->nCols;
|
||||
nRows = info->nRows;
|
||||
rowBytes = (info->nCols + 7) / 8;
|
||||
while ( (rowBytes % 2) != 0 ) {
|
||||
++rowBytes;
|
||||
}
|
||||
|
||||
bm = CreateBitmap( info->nCols, info->nRows, 1, 1, NULL );
|
||||
tmpDC = CreateCompatibleDC( hdc );
|
||||
SelectObject( tmpDC, bm );
|
||||
for ( row = 0; row < nRows; ++row ) {
|
||||
for ( col = 0; col < nCols; ++col ) {
|
||||
/* Optimize me... */
|
||||
XP_U8 byt = bits[col / 8];
|
||||
XP_Bool set = (byt & (0x80 >> (col % 8))) != 0;
|
||||
(void)SetPixel( tmpDC, col, row, set ? black:white );
|
||||
}
|
||||
bits += rowBytes;
|
||||
}
|
||||
DeleteDC( tmpDC );
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
BITMAP bmp;
|
||||
int nBytes = GetObject( bm, sizeof(bmp), &bmp );
|
||||
XP_ASSERT( nBytes > 0 );
|
||||
XP_ASSERT( bmp.bmWidth == nCols );
|
||||
XP_ASSERT( bmp.bmHeight == nRows );
|
||||
}
|
||||
#endif
|
||||
if ( canCache && entry->bms[index] != bm ) {
|
||||
XP_ASSERT( !entry->bms[index] || (entry->bms[index] == bm) );
|
||||
entry->bms[index] = bm;
|
||||
XP_LOGF( "%s: storing %p", __func__, bm );
|
||||
}
|
||||
}
|
||||
|
||||
*cached = canCache;
|
||||
return bm;
|
||||
} /* checkBMCache */
|
||||
|
||||
static void
|
||||
makeAndDrawBitmap( CEDrawCtx* dctx, HDC hdc, const RECT* bnds,
|
||||
const XP_UCHAR* letters, XP_U16 index,
|
||||
const XP_Bitmaps* bitmaps )
|
||||
{
|
||||
XP_Bool cached;
|
||||
HBITMAP bm = checkBMCache( dctx, hdc, letters, index, bitmaps, &cached );
|
||||
|
||||
ceDrawBitmapInRect( hdc, bnds, bm );
|
||||
|
||||
if ( !cached ) {
|
||||
DeleteObject( bm );
|
||||
}
|
||||
} /* makeAndDrawBitmap */
|
||||
|
||||
static void
|
||||
ceMeasureText( CEDrawCtx* dctx, HDC hdc, const FontCacheEntry* fce,
|
||||
const XP_UCHAR* str, XP_S16 padding,
|
||||
|
@ -807,7 +931,7 @@ ceSetBkColor( HDC hdc, const CEDrawCtx* dctx, XP_U16 index )
|
|||
DLSTATIC XP_Bool
|
||||
DRAW_FUNC_NAME(drawCell)( DrawCtx* p_dctx, const XP_Rect* xprect,
|
||||
const XP_UCHAR* letters,
|
||||
const XP_Bitmap XP_UNUSED(bitmap),
|
||||
const XP_Bitmaps* bitmaps,
|
||||
Tile XP_UNUSED(tile), XP_S16 owner,
|
||||
XWBonusType bonus, HintAtts hintAtts,
|
||||
CellFlags flags )
|
||||
|
@ -884,18 +1008,15 @@ DRAW_FUNC_NAME(drawCell)( DrawCtx* p_dctx, const XP_Rect* xprect,
|
|||
}
|
||||
|
||||
ceSetBkColor( hdc, dctx, bkIndex );
|
||||
ceSetTextColor( hdc, dctx, foreColorIndx );
|
||||
|
||||
if ( !isDragSrc && !!letters && (letters[0] != '\0') ) {
|
||||
if ( !isDragSrc && !!bitmaps ) {
|
||||
makeAndDrawBitmap( dctx, hdc, &rt, letters, 0, bitmaps );
|
||||
} else if ( !isDragSrc && !!letters && (letters[0] != '\0') ) {
|
||||
wchar_t widebuf[4];
|
||||
|
||||
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, letters, -1,
|
||||
widebuf, VSIZE(widebuf) );
|
||||
|
||||
ceSetTextColor( hdc, dctx, foreColorIndx );
|
||||
#ifndef _WIN32_WCE
|
||||
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, letters, -1,
|
||||
widebuf, VSIZE(widebuf) );
|
||||
#endif
|
||||
ceDrawTextClipped( hdc, widebuf, -1, XP_FALSE, fce, xprect->left+1,
|
||||
xprect->top+2, xprect->width, DT_CENTER );
|
||||
} else if ( (flags&CELL_ISSTAR) != 0 ) {
|
||||
|
@ -951,7 +1072,8 @@ DRAW_FUNC_NAME(trayBegin)( DrawCtx* p_dctx, const XP_Rect* XP_UNUSED(rect),
|
|||
|
||||
static void
|
||||
drawDrawTileGuts( DrawCtx* p_dctx, const XP_Rect* xprect,
|
||||
const XP_UCHAR* letters, XP_U16 val, CellFlags flags )
|
||||
const XP_UCHAR* letters, const XP_Bitmaps* bitmaps,
|
||||
XP_U16 val, CellFlags flags )
|
||||
{
|
||||
CEDrawCtx* dctx = (CEDrawCtx*)p_dctx;
|
||||
CEAppGlobals* globals = dctx->globals;
|
||||
|
@ -1015,9 +1137,17 @@ drawDrawTileGuts( DrawCtx* p_dctx, const XP_Rect* xprect,
|
|||
InsetRect( &rt, 1, 1 );
|
||||
}
|
||||
|
||||
if ( !!letters ) {
|
||||
fce = ceGetSizedFont( dctx, charHt, 0,
|
||||
valHidden ? RFONTS_TRAYNOVAL:RFONTS_TRAY );
|
||||
fce = ceGetSizedFont( dctx, charHt, 0,
|
||||
valHidden ? RFONTS_TRAYNOVAL:RFONTS_TRAY );
|
||||
|
||||
if ( !!bitmaps ) {
|
||||
RECT lrt = { .left = xprect->left,
|
||||
.top = xprect->top,
|
||||
.right = xprect->left + xprect->width - 8,
|
||||
.bottom = xprect->top + fce->glyphHt
|
||||
};
|
||||
makeAndDrawBitmap( dctx, hdc, &lrt, letters, 1, bitmaps );
|
||||
} else if ( !!letters ) {
|
||||
HFONT oldFont = SelectObject( hdc, fce->setFont );
|
||||
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, letters, -1,
|
||||
widebuf, VSIZE(widebuf) );
|
||||
|
@ -1046,21 +1176,22 @@ drawDrawTileGuts( DrawCtx* p_dctx, const XP_Rect* xprect,
|
|||
|
||||
DLSTATIC void
|
||||
DRAW_FUNC_NAME(drawTile)( DrawCtx* p_dctx, const XP_Rect* xprect,
|
||||
const XP_UCHAR* letters, XP_Bitmap XP_UNUSED(bitmap),
|
||||
const XP_UCHAR* letters, const XP_Bitmaps* bitmaps,
|
||||
XP_U16 val, CellFlags flags )
|
||||
{
|
||||
drawDrawTileGuts( p_dctx, xprect, letters, val, flags );
|
||||
drawDrawTileGuts( p_dctx, xprect, letters, bitmaps, val, flags );
|
||||
} /* ce_draw_drawTile */
|
||||
|
||||
#ifdef POINTER_SUPPORT
|
||||
DLSTATIC void
|
||||
DRAW_FUNC_NAME(drawTileMidDrag)( DrawCtx* p_dctx, const XP_Rect* xprect,
|
||||
const XP_UCHAR* letters,
|
||||
XP_Bitmap XP_UNUSED(bitmap),
|
||||
XP_U16 val, XP_U16 owner, CellFlags flags )
|
||||
const XP_Bitmaps* bitmaps, XP_U16 val,
|
||||
XP_U16 owner, CellFlags flags )
|
||||
{
|
||||
draw_trayBegin( p_dctx, xprect, owner, DFS_NONE );
|
||||
drawDrawTileGuts( p_dctx, xprect, letters, val, flags );
|
||||
if ( draw_trayBegin( p_dctx, xprect, owner, DFS_NONE ) ) {
|
||||
drawDrawTileGuts( p_dctx, xprect, letters, bitmaps, val, flags );
|
||||
}
|
||||
} /* ce_draw_drawTile */
|
||||
#endif
|
||||
|
||||
|
@ -1068,7 +1199,7 @@ DLSTATIC void
|
|||
DRAW_FUNC_NAME(drawTileBack)( DrawCtx* p_dctx, const XP_Rect* xprect,
|
||||
CellFlags flags )
|
||||
{
|
||||
drawDrawTileGuts( p_dctx, xprect, "?", 0, flags | CELL_VALHIDDEN );
|
||||
drawDrawTileGuts( p_dctx, xprect, "?", NULL, 0, flags | CELL_VALHIDDEN );
|
||||
} /* ce_draw_drawTileBack */
|
||||
|
||||
DLSTATIC void
|
||||
|
@ -1117,44 +1248,47 @@ ceDrawBitmapInRect( HDC hdc, const RECT* rect, HBITMAP bitmap )
|
|||
{
|
||||
BITMAP bmp;
|
||||
int nBytes;
|
||||
int left = rect->left;
|
||||
int top = rect->top;
|
||||
XP_U16 width = rect->right - left;
|
||||
XP_U16 height = rect->bottom - top;
|
||||
XP_U16 ii;
|
||||
HDC tmpDC;
|
||||
|
||||
XP_ASSERT( !!bitmap );
|
||||
nBytes = GetObject( bitmap, sizeof(bmp), &bmp );
|
||||
XP_ASSERT( nBytes > 0 );
|
||||
if ( nBytes == 0 ) {
|
||||
logLastError( "ceDrawBitmapInRect:GetObject" );
|
||||
} else {
|
||||
int left = rect->left;
|
||||
int top = rect->top;
|
||||
XP_U16 width = rect->right - left;
|
||||
XP_U16 height = rect->bottom - top;
|
||||
XP_U16 ii;
|
||||
HDC tmpDC;
|
||||
|
||||
for ( ii = 1;
|
||||
((bmp.bmWidth * ii) <= width) && ((bmp.bmHeight * ii) <= height);
|
||||
++ii ) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
if ( --ii == 0 ) {
|
||||
XP_LOGF( "%s: cell at %dx%d too small for bitmap at %ldx%ld",
|
||||
__func__, width, height, bmp.bmWidth, bmp.bmHeight );
|
||||
ii = 1;
|
||||
}
|
||||
|
||||
tmpDC = CreateCompatibleDC( hdc );
|
||||
SelectObject( tmpDC, bitmap );
|
||||
|
||||
(void)IntersectClipRect( tmpDC, left, top, rect->right, rect->bottom );
|
||||
|
||||
width = bmp.bmWidth * ii;
|
||||
height = bmp.bmHeight * ii;
|
||||
|
||||
left += ((rect->right - left) - width) / 2;
|
||||
top += ((rect->bottom - top) - height) / 2;
|
||||
|
||||
StretchBlt( hdc, left, top, width, height,
|
||||
tmpDC, 0, 0, bmp.bmHeight, bmp.bmWidth, SRCCOPY );
|
||||
DeleteDC( tmpDC );
|
||||
}
|
||||
|
||||
for ( ii = 1;
|
||||
((bmp.bmWidth * ii) <= width) && ((bmp.bmHeight * ii) <= height);
|
||||
++ii ) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
if ( --ii == 0 ) {
|
||||
XP_LOGF( "%s: cell too small for bitmap", __func__ );
|
||||
ii = 1;
|
||||
}
|
||||
|
||||
tmpDC = CreateCompatibleDC( hdc );
|
||||
SelectObject( tmpDC, bitmap );
|
||||
|
||||
(void)IntersectClipRect( tmpDC, left, top, rect->right, rect->bottom );
|
||||
|
||||
width = bmp.bmWidth * ii;
|
||||
height = bmp.bmHeight * ii;
|
||||
|
||||
left += ((rect->right - left) - width) / 2;
|
||||
top += ((rect->bottom - top) - height) / 2;
|
||||
|
||||
StretchBlt( hdc, left, top, width, height,
|
||||
tmpDC, 0, 0, bmp.bmHeight, bmp.bmWidth, SRCCOPY );
|
||||
DeleteDC( tmpDC );
|
||||
} /* ceDrawBitmapInRect */
|
||||
|
||||
DLSTATIC void
|
||||
|
@ -1604,18 +1738,15 @@ DRAW_FUNC_NAME(destroyCtxt)( DrawCtx* p_dctx )
|
|||
for ( ii = 0; ii < CE_NUM_COLORS; ++ii ) {
|
||||
DeleteObject( dctx->brushes[ii] );
|
||||
#ifdef DRAW_FOCUS_FRAME
|
||||
if ( !!dctx->pens[ii].pen ) {
|
||||
DeleteObject( dctx->pens[ii].pen );
|
||||
}
|
||||
ceDeleteObjectNotNull( dctx->pens[ii].pen );
|
||||
#endif
|
||||
}
|
||||
|
||||
for ( ii = 0; ii < VSIZE(dctx->hintPens); ++ii ) {
|
||||
if ( !!dctx->hintPens[ii] ) {
|
||||
DeleteObject( dctx->hintPens[ii] );
|
||||
}
|
||||
ceDeleteObjectNotNull( dctx->hintPens[ii] );
|
||||
}
|
||||
|
||||
ceClearBmCache( dctx );
|
||||
ceClearFontCache( dctx );
|
||||
|
||||
DeleteObject( dctx->rightArrow );
|
||||
|
@ -1635,6 +1766,8 @@ DRAW_FUNC_NAME(dictChanged)( DrawCtx* p_dctx, const DictionaryCtxt* dict )
|
|||
CEDrawCtx* dctx = (CEDrawCtx*)p_dctx;
|
||||
XP_ASSERT( !!dict );
|
||||
|
||||
ceClearBmCache( dctx );
|
||||
|
||||
/* If we don't yet have a dict, stick with the cache we have, which is
|
||||
either empty or came from the saved game and likely belong with the
|
||||
dict we're getting now. */
|
||||
|
@ -1703,9 +1836,7 @@ ce_draw_update( CEDrawCtx* dctx )
|
|||
XP_U16 ii;
|
||||
|
||||
for ( ii = 0; ii < CE_NUM_COLORS; ++ii ) {
|
||||
if ( !!dctx->brushes[ii] ) {
|
||||
DeleteObject( dctx->brushes[ii] );
|
||||
}
|
||||
ceDeleteObjectNotNull( dctx->brushes[ii] );
|
||||
dctx->brushes[ii] = CreateSolidBrush(dctx->globals->appPrefs.colors[ii]);
|
||||
}
|
||||
} /* ce_drawctxt_update */
|
||||
|
|
Loading…
Reference in a new issue