diff options
Diffstat (limited to 'app/wlib/mswlib/mswdraw.c')
-rw-r--r-- | app/wlib/mswlib/mswdraw.c | 1783 |
1 files changed, 1783 insertions, 0 deletions
diff --git a/app/wlib/mswlib/mswdraw.c b/app/wlib/mswlib/mswdraw.c new file mode 100644 index 0000000..498b49e --- /dev/null +++ b/app/wlib/mswlib/mswdraw.c @@ -0,0 +1,1783 @@ +/* + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswdraw.c,v 1.6 2009-05-15 18:16:16 m_fischer Exp $ + */ + +#define _WIN32_WINNT 0x0500 /* for wheel mouse supposrt */ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <winuser.h> + +#ifdef WIN32 +#define wFont_t tagLOGFONTA +#else +#define wFont_t tagLOGFONT +#endif +#include "mswint.h" + +/* + ***************************************************************************** + * + * Draw + * + ***************************************************************************** + */ + +static wBool_t initted = FALSE; + +long wDebugFont; + +static FARPROC oldDrawProc; + + +static long tmpOp = 0x990066; +static long setOp = 0x8800c6; +static long clrOp = 0xbb0226; + +#define CENTERMARK_LENGTH 6 + +#ifdef SLOW +static wPos_t XPIX2INCH( wDraw_p d, int ix ) +{ + return (wPos_t)ix; +} + +static wPos_t YPIX2INCH( wDraw_p d, int iy ) +{ + wPos_t y; + y = (wPos_t)(d->h-2-iy); + return y; +} + +static int XINCH2PIX( wDraw_p d, wPos_t xx ) +{ + int ix; + ix = (int)(xx); + return ix; +} + +static int YINCH2PIX( wDraw_p d, wPos_t y ) +{ + int iy; + iy = d->h-2 - (int)(y); + return iy; +} + + +static wPos_t XPIXELSTOINCH( wDraw_p d, int ix ) +{ + return (wPos_t)ix; +} + + +static wPos_t YPIXELSTOINCH( wDraw_p d, int iy ) +{ + return (wPos_t)iy; +} +#else +#define XPIX2INCH( d, ix ) \ + ((wPos_t)ix) + +#define YPIX2INCH( d, iy ) \ + ((wPos_t)(d->h-2-iy)) + +#define XINCH2PIX( d, xx ) \ + ((int)(xx)) + +#define YINCH2PIX( d, y ) \ + (d->h-2 - (int)(y)) + + +#define XPIXELSTOINCH( d, ix ) \ + ((wPos_t)ix) + + +#define YPIXELSTOINCH( d, iy ) \ + ((wPos_t)iy) + +#endif + +/* + ***************************************************************************** + * + * Basic Line Draw + * + ***************************************************************************** + */ + + + +static long noNegDrawArgs = -1; +static long noFlatEndCaps = 0; + +void wDrawDelayUpdate( + wDraw_p d, + wBool_t delay ) +{ +} + +/** + * Sets the proper pen and composition for the next drawing operation + * + * + * \param hDc IN device context + * \param d IN ??? + * \param dw IN line width + * \param lt IN line type (dashed, solid, ...) + * \param dc IN color + * \param dopt IN ???? + */ + +static void setDrawMode( + HDC hDc, + wDraw_p d, + wDrawWidth dw, + wDrawLineType_e lt, + wDrawColor dc, + wDrawOpts dopt ) +{ + int mode; + HPEN hOldPen; + static wDraw_p d0; + static wDrawWidth dw0 = -1; + static wDrawLineType_e lt0 = (wDrawLineType_e)-1; + static wDrawColor dc0 = -1; + static int mode0 = -1; + static LOGBRUSH logBrush = { 0, 0, 0 }; + DWORD penStyle; + + if ( d->hasPalette ) { + int winPaletteClock = mswGetPaletteClock(); + if ( d->paletteClock < winPaletteClock ) { + RealizePalette( hDc ); + d->paletteClock = winPaletteClock; + } + } + + if (dopt & wDrawOptTemp) { + mode = R2_NOTXORPEN; + } else { + mode = R2_COPYPEN; + } + SetROP2( hDc, mode ); + if ( d == d0 && mode == mode0 && dw0 == dw && lt == lt0 && dc == dc0 ) + return; + + // make sure that the line width is at least 1! + if( !dw ) + dw++; + + d0 = d; mode0 = mode; dw0 = dw; lt0 = lt; dc0 = dc; + + logBrush.lbColor = mswGetColor(d->hasPalette,dc); + if ( lt==wDrawLineSolid ) { + penStyle = PS_GEOMETRIC | PS_SOLID; + if ( noFlatEndCaps == FALSE ) + penStyle |= PS_ENDCAP_FLAT; + d->hPen = ExtCreatePen( penStyle, + dw, + &logBrush, + 0, + NULL ); + /*colorPalette.palPalEntry[dc] );*/ + } else { + d->hPen = CreatePen( PS_DOT, 0, mswGetColor( d->hasPalette, dc ) ); + } + hOldPen = SelectObject( hDc, d->hPen ); + DeleteObject( hOldPen ); +} + +static void setDrawBrush( + HDC hDc, + wDraw_p d, + wDrawColor dc, + wDrawOpts dopt ) +{ + HBRUSH hOldBrush; + static wDraw_p d0; + static wDrawColor dc0 = -1; + + setDrawMode( hDc, d, 0, wDrawLineSolid, dc, dopt ); + if ( d == d0 && dc == dc0 ) + return; + + d0 = d; dc0 = dc; + + d->hBrush = CreateSolidBrush( + mswGetColor(d->hasPalette,dc) ); + hOldBrush = SelectObject( hDc, d->hBrush ); + DeleteObject( hOldBrush ); +} + + +static void myInvalidateRect( + wDraw_p d, + RECT * prect ) +{ + if ( prect->top < 0 ) prect->top = 0; + if ( prect->left < 0 ) prect->left = 0; + if ( prect->bottom > d->h ) prect->bottom = d->h; + if ( prect->right > d->w ) prect->right = d->w; + InvalidateRect( d->hWnd, prect, FALSE ); +} + + +static int clip0( POINT * p0, POINT * p1, wDraw_p d ) +{ + long int x0=p0->x, y0=p0->y, x1=p1->x, y1=p1->y; + long int dx, dy; + if ( x0<0 && x1<0 ) return 0; + if ( y0<0 && y1<0 ) return 0; + dx=x1-x0; + dy=y1-y0; + if ( x0 < 0 ) { + y0 -= x0*dy/dx; + x0 = 0; + } + if ( y0 < 0 ) { + if ( (x0 -= y0*dx/dy) < 0 ) return 0; + y0 = 0; + } + if ( x1 < 0 ) { + y1 -= x1*dy/dx; + x1 = 0; + } + if ( y1 < 0 ) { + if ( (x1 -= y1*dx/dy) < 0 ) return 0; + y1 = 0; + } + p0->x = (int)x0; + p0->y = (int)y0; + p1->x = (int)x1; + p1->y = (int)y1; + return 1; +} + + +void wDrawLine( + wDraw_p d, + wPos_t p0x, + wPos_t p0y, + wPos_t p1x, + wPos_t p1y, + wDrawWidth dw, + wDrawLineType_e lt, + wDrawColor dc, + wDrawOpts dopt ) +{ + POINT p0, p1; + RECT rect; + setDrawMode( d->hDc, d, dw, lt, dc, dopt ); + p0.x = XINCH2PIX(d,p0x); + p0.y = YINCH2PIX(d,p0y); + p1.x = XINCH2PIX(d,p1x); + p1.y = YINCH2PIX(d,p1y); + if ( noNegDrawArgs>0 && !clip0( &p0, &p1, d ) ) + return; + MoveTo( d->hDc, p0.x, p0.y ); + LineTo( d->hDc, p1.x, p1.y ); + if (d->hWnd) { + if (dw==0) + dw = 1; + dw++; + if (p0.y<p1.y) { + rect.top = p0.y-dw; + rect.bottom = p1.y+dw; + } else { + rect.top = p1.y-dw; + rect.bottom = p0.y+dw; + } + if (p0.x<p1.x) { + rect.left = p0.x-dw; + rect.right = p1.x+dw; + } else { + rect.left = p1.x-dw; + rect.right = p0.x+dw; + } + myInvalidateRect( d, &rect ); + } +} + +static double mswsin( double angle ) +{ + while (angle < 0.0) angle += 360.0; + while (angle >= 360.0) angle -= 360.0; + angle *= (M_PI*2.0)/360.0; + return sin( angle ); +} + +static double mswcos( double angle ) +{ + while (angle < 0.0) angle += 360.0; + while (angle >= 360.0) angle -= 360.0; + angle *= (M_PI*2.0)/360.0; + return cos( angle ); +} + +static double mswasin( double x, double h ) +{ + double angle; + angle = asin( x/h ); + angle /= (M_PI*2.0)/360.0; + return angle; +} + +/** + * Draw an arc around a specified center + * + * \param d IN ? + * \param px, py IN center of arc + * \param r IN radius + * \param a0, a1 IN start and end angle + * \param drawCenter draw marking for center + * \param dw line width + * \param lt line type + * \param dc color + * \param dopt ? + */ + + +void wDrawArc( + wDraw_p d, + wPos_t px, + wPos_t py, + wPos_t r, + double a0, + double a1, + int drawCenter, + wDrawWidth dw, + wDrawLineType_e lt, + wDrawColor dc, + wDrawOpts dopt ) +{ + int i, cnt; + POINT p0, p1, ps, pe, pp0, pp1, pp2, pc; + double psx, psy, pex, pey, len, aa; + RECT rect; + int needMoveTo; + wBool_t fakeArc = FALSE; + + len = a1/360.0 * (2 * M_PI) * r; + if (len < 3) + return; + + p0.x = XINCH2PIX(d,px-r); + p0.y = YINCH2PIX(d,py+r)+1; + p1.x = XINCH2PIX(d,px+r); + p1.y = YINCH2PIX(d,py-r)+1; + + pex = px + r * mswsin(a0); + pey = py + r * mswcos(a0); + psx = px + r * mswsin(a0+a1); + psy = py + r * mswcos(a0+a1); + + /*pointOnCircle( &pe, p, r, a0 ); + pointOnCircle( &ps, p, r, a0+a1 );*/ + ps.x = XINCH2PIX(d,(wPos_t)psx); + ps.y = YINCH2PIX(d,(wPos_t)psy); + pe.x = XINCH2PIX(d,(wPos_t)pex); + pe.y = YINCH2PIX(d,(wPos_t)pey); + + setDrawMode( d->hDc, d, dw, lt, dc, dopt ); + + if (dw == 0) + dw = 1; + + if (r>4096) { + /* The book says 32K but experience says otherwise */ + fakeArc = TRUE; + } + if ( noNegDrawArgs > 0 ) { + if ( p0.x < 0 || p0.y < 0 || p1.x < 0 || p1.y < 0 ) + fakeArc = TRUE; + } + if ( fakeArc ) { + cnt = (int)a1; + if ( cnt <= 0 ) cnt = 1; + if ( cnt > 360 ) cnt = 360; + aa = a1 / cnt; + psx = px + r * mswsin(a0); + psy = py + r * mswcos(a0); + pp0.x = XINCH2PIX( d, (wPos_t)psx ); + pp0.y = YINCH2PIX( d, (wPos_t)psy ); + needMoveTo = TRUE; + for ( i=0; i<cnt; i++ ) { + a0 += aa; + psx = px + r * mswsin(a0); + psy = py + r * mswcos(a0); + pp2.x = pp1.x = XINCH2PIX( d, (wPos_t)psx ); + pp2.y = pp1.y = YINCH2PIX( d, (wPos_t)psy ); + if ( clip0( &pp0, &pp1, d ) ) { + if (needMoveTo) { + MoveTo( d->hDc, pp0.x, pp0.y ); + needMoveTo = FALSE; + } + LineTo( d->hDc, pp1.x, pp1.y ); + } else { + needMoveTo = TRUE; + } + pp0.x = pp2.x; pp0.y = pp2.y; + } + } else { + if ( a0 == 0.0 && a1 == 360.0 ) { + Arc( d->hDc, p0.x, p1.y, p1.x, p0.y, ps.x, p0.y-1, pe.x, p1.y-1 ); + Arc( d->hDc, p0.x, p1.y, p1.x, p0.y, ps.x, p1.y-1, pe.x, p0.y-1 ); + } else { + Arc( d->hDc, p0.x, p1.y, p1.x, p0.y, ps.x, ps.y, pe.x, pe.y ); + } + } + + // should the center of the arc be drawn? + if( drawCenter ) { + + // calculate the center coordinates + pc.x = XINCH2PIX( d, px ); + pc.y = YINCH2PIX( d, py ); + // now draw the crosshair + MoveTo( d->hDc, pc.x - CENTERMARK_LENGTH/2, pc.y ); + LineTo( d->hDc, pc.x + CENTERMARK_LENGTH/2, pc.y ); + MoveTo( d->hDc, pc.x, pc.y - CENTERMARK_LENGTH/2 ); + LineTo( d->hDc, pc.x, pc.y + CENTERMARK_LENGTH/2 ); + + // invalidate the area of the crosshair + rect.top = pc.y - CENTERMARK_LENGTH / 2 - 1; + rect.bottom = pc.y + CENTERMARK_LENGTH / 2 + 1; + rect.left = pc.x - CENTERMARK_LENGTH / 2 - 1; + rect.right = pc.x + CENTERMARK_LENGTH / 2 + 1; + myInvalidateRect( d, &rect ); + } + + if (d->hWnd) { + dw++; + a1 += a0; + if (a1>360.0) + rect.top = p0.y; + else + rect.top = min(pe.y,ps.y); + if (a1>(a0>180?360.0:0.0)+180) + rect.bottom = p1.y; + else + rect.bottom = max(pe.y,ps.y); + if (a1>(a0>270?360.0:0.0)+270) + rect.left = p0.x; + else + rect.left = min(pe.x,ps.x); + if (a1>(a0>90?360.0:0.0)+90) + rect.right = p1.x; + else + rect.right = max(pe.x,ps.x); + rect.top -= dw; + rect.bottom += dw; + rect.left -= dw; + rect.right += dw; + myInvalidateRect( d, &rect ); + + } +} + +void wDrawPoint( + wDraw_p d, + wPos_t px, + wPos_t py, + wDrawColor dc, + wDrawOpts dopt ) +{ + POINT p0; + RECT rect; + + p0.x = XINCH2PIX(d,px); + p0.y = YINCH2PIX(d,py); + + if ( p0.x < 0 || p0.y < 0 ) + return; + if ( p0.x >= d->w || p0.y >= d->h ) + return; + setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt ); + + SetPixel( d->hDc, p0.x, p0.y, mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/ ); + if (d->hWnd) { + rect.top = p0.y-1; + rect.bottom = p0.y+1; + rect.left = p0.x-1; + rect.right = p0.x+1; + myInvalidateRect( d, &rect ); + } +} + +/* + ***************************************************************************** + * + * Fonts + * + ***************************************************************************** + */ + + +static LOGFONT logFont = { + /* Initial default values */ + -24, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" }; + +static LOGFONT timesFont[2][2] = { + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" } }, + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" } } }; + +static LOGFONT helvFont[2][2] = { + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" } }, + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Hevletica" } } }; + + +void mswFontInit( void ) +{ + const char * face; + long size; + face = wPrefGetString( "msw window font", "face" ); + wPrefGetInteger( "msw window font", "size", &size, -24 ); + if (face) { + strncpy( logFont.lfFaceName, face, LF_FACESIZE ); + } + logFont.lfHeight = (int)size; +} + + +static CHOOSEFONT chooseFont; +static wFontSize_t fontSize = 18; +static double fontFactor = 1.0; + +static void doChooseFont( void ) +{ + int rc; + memset( &chooseFont, 0, sizeof chooseFont ); + chooseFont.lStructSize = sizeof chooseFont; + chooseFont.hwndOwner = mswHWnd; + chooseFont.lpLogFont = &logFont; + chooseFont.Flags = CF_SCREENFONTS|CF_SCALABLEONLY|CF_INITTOLOGFONTSTRUCT; + chooseFont.nFontType = SCREEN_FONTTYPE; + rc = ChooseFont( &chooseFont ); + if (rc) { + fontSize = (wFontSize_t)(-logFont.lfHeight * 72) / 96.0 / fontFactor; + if (fontSize < 1) + fontSize = 1; + wPrefSetString( "msw window font", "face", logFont.lfFaceName ); + wPrefSetInteger( "msw window font", "size", logFont.lfHeight ); + } +} + +static int computeFontSize( wDraw_p d, double siz ) +{ + int ret; + siz = (siz * d->DPI) / 72.0; + ret = (int)(siz * fontFactor); + if (ret < 1) + ret = 1; + return -ret; +} + +void wDrawGetTextSize( + wPos_t *w, + wPos_t *h, + wPos_t *d, + wDraw_p bd, + const char * text, + wFont_p fp, + double siz ) +{ + int x, y; + HFONT newFont, prevFont; + DWORD extent; + int oldLfHeight; + if (fp == NULL) + fp = &logFont; + fp->lfEscapement = 0; + oldLfHeight = fp->lfHeight; + fp->lfHeight = computeFontSize( bd, siz ); + fp->lfWidth = 0; + newFont = CreateFontIndirect( fp ); + prevFont = SelectObject( bd->hDc, newFont ); + extent = GetTextExtent( bd->hDc, CAST_AWAY_CONST text, strlen(text) ); + x = LOWORD(extent); + y = HIWORD(extent); + *w = XPIXELSTOINCH( bd, x ); + *h = YPIXELSTOINCH( bd, y ); + *d = 0; + SelectObject( bd->hDc, prevFont ); + DeleteObject( newFont ); + fp->lfHeight = oldLfHeight; +} + +void wDrawString( + wDraw_p d, + wPos_t px, + wPos_t py, + double angle, + const char * text, + wFont_p fp, + double siz, + wDrawColor dc, + wDrawOpts dopts ) +{ + int x, y; + HFONT newFont, prevFont; + HDC newDc; + HBITMAP oldBm, newBm; + DWORD extent; + int w, h; + RECT rect; + int oldLfHeight; + + if (fp == NULL) + fp = &logFont; + oldLfHeight = fp->lfHeight; + fp->lfEscapement = (int)(angle*10.0); + fp->lfHeight = computeFontSize( d, siz ); + fp->lfWidth = 0; + newFont = CreateFontIndirect( fp ); + x = XINCH2PIX(d,px) + (int)(mswsin(angle)*fp->lfHeight-0.5); + y = YINCH2PIX(d,py) + (int)(mswcos(angle)*fp->lfHeight-0.5); + if ( noNegDrawArgs > 0 && ( x < 0 || y < 0 ) ) + return; + if (dopts & wDrawOptTemp) { + setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopts ); + newDc = CreateCompatibleDC( d->hDc ); + prevFont = SelectObject( newDc, newFont ); + extent = GetTextExtent( newDc, CAST_AWAY_CONST text, strlen(text) ); + w = LOWORD(extent); + h = HIWORD(extent); + if ( h > w ) w = h; + newBm = CreateCompatibleBitmap( d->hDc, w*2, w*2 ); + oldBm = SelectObject( newDc, newBm ); + rect.top = rect.left = 0; + rect.bottom = rect.right = w*2; + FillRect( newDc, &rect, GetStockObject(WHITE_BRUSH) ); + TextOut( newDc, w, w, text, strlen(text) ); + BitBlt( d->hDc, x-w, y-w, w*2, w*2, newDc, 0, 0, tmpOp ); + SelectObject( newDc, oldBm ); + DeleteObject( newBm ); + SelectObject( newDc, prevFont ); + DeleteDC( newDc ); + if (d->hWnd) { + rect.top = y-(w+1); + rect.bottom = y+(w+1); + rect.left = x-(w+1); + rect.right = x+(w+1); + myInvalidateRect( d, &rect ); + } +#ifdef LATER + /* KLUDGE: Can't Invert text, so we just draw a bow - a pox on windows*/ + MoveTo( d->hDc, x, y ); + LineTo( d->hDc, x+w, y ); + LineTo( d->hDc, x+w, y+h ); + LineTo( d->hDc, x, y+h ); + LineTo( d->hDc, x, y ); +#endif + } else { + prevFont = SelectObject( d->hDc, newFont ); + SetBkMode( d->hDc, TRANSPARENT ); + if (dc != wDrawColorBlack) { + COLORREF old; + old = SetTextColor( d->hDc, mswGetColor(d->hasPalette,dc)/*colorPalette.palPalEntry[dc]*/ ); + TextOut( d->hDc, x, y, text, strlen(text) ); + SetTextColor( d->hDc, old ); + } else + TextOut( d->hDc, x, y, text, strlen(text) ); + extent = GetTextExtent( d->hDc, CAST_AWAY_CONST text, strlen(text) ); + SelectObject( d->hDc, prevFont ); + w = LOWORD(extent); + h = HIWORD(extent); + if (d->hWnd) { + rect.top = y-(w+h+1); + rect.bottom = y+(w+h+1); + rect.left = x-(w+h+1); + rect.right = x+(w+h+1); + myInvalidateRect( d, &rect ); + } + } + DeleteObject( newFont ); + fp->lfHeight = oldLfHeight; +} + +static const char * wCurFont( void ) +{ + return logFont.lfFaceName; +} + +void wInitializeFonts() +{ +} + +wFont_p wStandardFont( int family, wBool_t bold, wBool_t italic ) +{ + if (family == F_TIMES) + return ×Font[bold][italic]; + else if (family == F_HELV) + return &helvFont[bold][italic]; + else + return NULL; +} + +void wSelectFont( const char * title ) +{ + doChooseFont(); +} + + +wFontSize_t wSelectedFontSize( void ) +{ + return fontSize; +} + +void wSetSelectedFontSize(int size) +{ + fontSize = (wFontSize_t)size; +} + +/* + ***************************************************************************** + * + * Misc + * + ***************************************************************************** + */ + + + +void wDrawFilledRectangle( + wDraw_p d, + wPos_t px, + wPos_t py, + wPos_t sx, + wPos_t sy, + wDrawColor color, + wDrawOpts opts ) +{ + RECT rect; + if (d == NULL) + return; + setDrawBrush( d->hDc, d, color, opts ); + rect.left = XINCH2PIX(d,px); + rect.right = XINCH2PIX(d,px+sx); + rect.top = YINCH2PIX(d,py+sy); + rect.bottom = YINCH2PIX(d,py); + if ( rect.right < 0 || + rect.bottom < 0 ) + return; + if ( rect.left < 0 ) + rect.left = 0; + if ( rect.top < 0 ) + rect.top = 0; + if ( rect.left > d->w || + rect.top > d->h ) + return; + if ( rect.right > d->w ) + rect.right = d->w; + if ( rect.bottom > d->h ) + rect.bottom = d->h; + Rectangle( d->hDc, rect.left, rect.top, rect.right, rect.bottom ); + if (d->hWnd) { + rect.top--; + rect.left--; + rect.bottom++; + rect.right++; + myInvalidateRect( d, &rect ); + } +} + +#ifdef DRAWFILLPOLYLOG +static FILE * logF; +#endif +static int wFillPointsMax = 0; +static POINT * wFillPoints; + +static void addPoint( + int * pk, + POINT * pp, + RECT * pr ) +{ +#ifdef DRAWFILLPOLYLOG +fprintf( logF, " q[%d] = {%d,%d}\n", *pk, pp->x, pp->y ); +#endif + if ( *pk > 0 && + wFillPoints[(*pk)-1].x == pp->x && wFillPoints[(*pk)-1].y == pp->y ) + return; + wFillPoints[ (*pk)++ ] = *pp; + if (pp->x<pr->left) + pr->left = pp->x; + if (pp->x>pr->right) + pr->right = pp->x; + if (pp->y<pr->top) + pr->top = pp->y; + if (pp->y>pr->bottom) + pr->bottom = pp->y; +} + +void wDrawFilledPolygon( + wDraw_p d, + wPos_t p[][2], + int cnt, + wDrawColor color, + wDrawOpts opts ) +{ + RECT rect; + int i, k; + POINT p0, p1, q0, q1; + static POINT zero = { 0, 0 }; + wBool_t p1Clipped; + + if (d == NULL) + return; + if (cnt*2 > wFillPointsMax) { + wFillPoints = realloc( wFillPoints, cnt * 2 * sizeof *(POINT*)NULL ); + wFillPointsMax = cnt*2; + } + setDrawBrush( d->hDc, d, color, opts ); + p1.x = rect.left = rect.right = XINCH2PIX(d,p[cnt-1][0]-1); + p1.y = rect.top = rect.bottom = YINCH2PIX(d,p[cnt-1][1]+1); +#ifdef DRAWFILLPOLYLOG +logF = fopen( "log.txt", "a" ); +fprintf( logF, "\np[%d] = {%d,%d}\n", cnt-1, p1.x, p1.y ); +#endif + p1Clipped = FALSE; + for ( i=k=0; i<cnt; i++ ) { + p0 = p1; + p1.x = XINCH2PIX(d,p[i][0]-1); + p1.y = YINCH2PIX(d,p[i][1]+1); +#ifdef DRAWFILLPOLYLOG +fprintf( logF, "p[%d] = {%d,%d}\n", i, p1.x, p1.y ); +#endif + q0 = p0; + q1 = p1; + if ( clip0( &q0, &q1, NULL ) ) { +#ifdef DRAWFILLPOLYLOG +fprintf( logF, " clip( {%d,%d} {%d,%d} ) = {%d,%d} {%d,%d}\n", p0.x, p0.y, p1.x, p1.y, q0.x, q0.y, q1.x, q1.y ); +#endif + if ( q0.x != p0.x || q0.y != p0.y ) { + if ( k > 0 && ( q0.x > q0.y ) != ( wFillPoints[k-1].x > wFillPoints[k-1].y ) ) + addPoint( &k, &zero, &rect ); + addPoint( &k, &q0, &rect ); + } + addPoint( &k, &q1, &rect ); + p1Clipped = ( q1.x != p1.x || q1.y != p1.y ); + } + } + if ( p1Clipped && + ( wFillPoints[k-1].x > wFillPoints[k-1].y ) != ( wFillPoints[0].x > wFillPoints[0].y ) ) + addPoint( &k, &zero, &rect ); +#ifdef DRAWFILLPOLYLOG +fflush( logF ); +fclose( logF ); +#endif + if ( k <= 2 ) + return; + Polygon( d->hDc, wFillPoints, k ); + if (d->hWnd) { + rect.top--; + rect.left--; + rect.bottom++; + rect.right++; + myInvalidateRect( d, &rect ); + } +} + +#define MAX_FILLCIRCLE_POINTS (30) +void wDrawFilledCircle( + wDraw_p d, + wPos_t x, + wPos_t y, + wPos_t r, + wDrawColor color, + wDrawOpts opts ) +{ + POINT p0, p1; + RECT rect; + static wPos_t circlePts[MAX_FILLCIRCLE_POINTS][2]; + int inx, cnt; + double dang; + + p0.x = XINCH2PIX(d,x-r); + p0.y = YINCH2PIX(d,y+r)+1; + p1.x = XINCH2PIX(d,x+r); + p1.y = YINCH2PIX(d,y-r)+1; + + setDrawBrush( d->hDc, d, color, opts ); + if ( noNegDrawArgs > 0 && ( p0.x < 0 || p0.y < 0 ) ) { + if ( r > MAX_FILLCIRCLE_POINTS ) + cnt = MAX_FILLCIRCLE_POINTS; + else if ( r > 8 ) + cnt = r; + else + cnt = 8; + dang = 360.0/cnt; + for ( inx=0; inx<cnt; inx++ ) { + circlePts[inx][0] = x + (int)(r * mswcos( inx*dang ) + 0.5 ); + circlePts[inx][1] = y + (int)(r * mswsin( inx*dang ) + 0.5 ); + } + wDrawFilledPolygon( d, circlePts, cnt, color, opts ); + } else { + Ellipse( d->hDc, p0.x, p0.y, p1.x, p1.y ); + if (d->hWnd) { + rect.top = p0.y; + rect.bottom = p1.y; + rect.left = p0.x; + rect.right = p1.x; + myInvalidateRect( d, &rect ); + } + } +} + +/* + ***************************************************************************** + * + * Misc + * + ***************************************************************************** + */ + + +void wDrawSaveImage( + wDraw_p bd ) +{ + if ( bd->hBmBackup ) { + SelectObject( bd->hDcBackup, bd->hBmBackupOld ); + DeleteObject( bd->hBmBackup ); + bd->hBmBackup = (HBITMAP)0; + } + if ( bd->hDcBackup == (HDC)0 ) + bd->hDcBackup = CreateCompatibleDC( bd->hDc ); + bd->hBmBackup = CreateCompatibleBitmap( bd->hDc, bd->w, bd->h ); + bd->hBmBackupOld = SelectObject( bd->hDcBackup, bd->hBmBackup ); + BitBlt( bd->hDcBackup, 0, 0, bd->w, bd->h, bd->hDc, 0, 0, SRCCOPY ); +} + +void wDrawRestoreImage( + wDraw_p bd ) +{ + if ( bd->hBmBackup == (HBITMAP)0 ) { + mswFail( "wDrawRestoreImage: hBmBackup == 0" ); + return; + } + BitBlt( bd->hDc, 0, 0, bd->w, bd->h, bd->hDcBackup, 0, 0, SRCCOPY ); + InvalidateRect( bd->hWnd, NULL, FALSE ); +} + + +void wDrawClear( wDraw_p d ) +{ + RECT rect; + SetROP2( d->hDc, R2_WHITE ); + Rectangle( d->hDc, 0, 0, d->w, d->h ); + if (d->hWnd) { + rect.top = 0; + rect.bottom = d->h; + rect.left = 0; + rect.right = d->w; + InvalidateRect( d->hWnd, &rect, FALSE ); + } +} + + +void wDrawSetSize( + wDraw_p d, + wPos_t width, + wPos_t height ) +{ + d->w = width; + d->h = height; + if (!SetWindowPos( d->hWnd, HWND_TOP, 0, 0, + d->w, d->h, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("wDrawSetSize: SetWindowPos"); + } + /*wRedraw( d );*/ +} + + +void wDrawGetSize( + wDraw_p d, + wPos_t * width, + wPos_t * height ) +{ + *width = d->w-2; + *height = d->h-2; +} + + +void * wDrawGetContext( wDraw_p d ) +{ + return d->data; +} + + +double wDrawGetDPI( wDraw_p d ) +{ + return d->DPI; +} + +double wDrawGetMaxRadius( wDraw_p d ) +{ + return 4096.0; +} + +void wDrawClip( + wDraw_p d, + wPos_t x, + wPos_t y, + wPos_t w, + wPos_t h ) +{ + int ix0, iy0, ix1, iy1; + HRGN hRgnClip; + ix0 = XINCH2PIX(d,x); + iy0 = YINCH2PIX(d,y); + ix1 = XINCH2PIX(d,x+w); + iy1 = YINCH2PIX(d,y+h); + /* Note: Ydim is upside down so iy1<iy0 */ + hRgnClip = CreateRectRgn( ix0, iy1, ix1, iy0 ); + SelectClipRgn( d->hDc, hRgnClip ); + DeleteObject( hRgnClip ); +} + + +void wRedraw( wDraw_p d ) +{ + wDrawClear( d ); + if (d->drawRepaint) + d->drawRepaint( d, d->data, 0, 0 ); +} + +/* + ***************************************************************************** + * + * BitMap + * + ***************************************************************************** + */ + +struct wDrawBitMap_t { + wDrawBitMap_p next; + wPos_t x; + wPos_t y; + wPos_t w; + wPos_t h; + char * bmx; + wDrawColor color; + HBITMAP bm; + }; +wDrawBitMap_p bmRoot = NULL; + + +void wDrawBitMap( + wDraw_p d, + wDrawBitMap_p bm, + wPos_t px, + wPos_t py, + wDrawColor dc, + wDrawOpts dopt ) +{ + HDC bmDc, hDc; + HBITMAP oldBm; + DWORD mode; + int x0, y0; + RECT rect; + + x0 = XINCH2PIX(d,px-bm->x); + y0 = YINCH2PIX(d,py-bm->y+bm->h); +#ifdef LATER + if ( noNegDrawArgs > 0 && ( x0 < 0 || y0 < 0 ) ) + return; +#endif + if (dopt & wDrawOptTemp) { + mode = tmpOp; + } else if (dc == wDrawColorWhite) { + mode = clrOp; + dc = wDrawColorBlack; + } else { + mode = setOp; + } + + if ( bm->color != dc ) { + if ( bm->bm ) + DeleteObject( bm->bm ); + bm->bm = mswCreateBitMap( mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/, RGB( 255, 255, 255 ), + RGB( 255, 255, 255 ), bm->w, bm->h, bm->bmx ); + bm->color = dc; + } + if ( (dopt & wDrawOptNoClip) != 0 && + ( px < 0 || px >= d->w || py < 0 || py >= d->h ) ) { + x0 += d->x; + y0 += d->y; + hDc = GetDC( ((wControl_p)(d->parent))->hWnd ); + bmDc = CreateCompatibleDC( hDc ); + oldBm = SelectObject( bmDc, bm->bm ); + BitBlt( hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, tmpOp ); + SelectObject( bmDc, oldBm ); + DeleteDC( bmDc ); + ReleaseDC( ((wControl_p)(d->parent))->hWnd, hDc ); + return; + } + + bmDc = CreateCompatibleDC( d->hDc ); + setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt ); + oldBm = SelectObject( bmDc, bm->bm ); + BitBlt( d->hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, mode ); + SelectObject( bmDc, oldBm ); + DeleteDC( bmDc ); + if (d->hWnd) { + rect.top = y0-1; + rect.bottom = rect.top+bm->h+1; + rect.left = x0-1; + rect.right = rect.left+bm->w+1; + myInvalidateRect( d, &rect ); + } +} + + +wDrawBitMap_p wDrawBitMapCreate( + wDraw_p d, + int w, + int h, + int x, + int y, + const char * bits ) +{ + wDrawBitMap_p bm; + int bmSize = ((w+7)/8) * h; + bm = (wDrawBitMap_p)malloc( sizeof *bm ); + if (bmRoot == NULL) { + bmRoot = bm; + bm->next = NULL; + } else { + bm->next = bmRoot; + bmRoot = bm; + } + bm->x = x; + bm->y = y; + bm->w = w; + bm->h = h; + bm->bmx = malloc( bmSize ); + bm->bm = (HBITMAP)0; + bm->color = -1; + memcpy( bm->bmx, bits, bmSize ); + /*bm->bm = mswCreateBitMap( GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), w, h, bits );*/ + return bm; +} + +/* + ***************************************************************************** + * + * Create + * + ***************************************************************************** + */ + +int doSetFocus = 1; + +long FAR PASCAL XEXPORT mswDrawPush( + HWND hWnd, + UINT message, + UINT wParam, + LONG lParam ) +{ +#ifdef WIN32 + long inx = GetWindowLong( hWnd, GWL_ID ); +#else + short inx = GetWindowWord( hWnd, GWW_ID ); +#endif + wDraw_p b; + short int ix, iy; + wPos_t x, y; + HDC hDc; + PAINTSTRUCT ps; + wAction_t action; + RECT rect; + HWND activeWnd; + HWND focusWnd; + wAccelKey_e extChar; + + switch( message ) { + case WM_CREATE: + b = (wDraw_p)mswMapIndex( inx ); + hDc = GetDC(hWnd); + if ( b->option & BD_DIRECT ) { + b->hDc = hDc; + b->hBm = 0; + b->hBmOld = 0; + } else { + b->hDc = CreateCompatibleDC( hDc ); + b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); + b->hBmOld = SelectObject( b->hDc, b->hBm ); + } + if (mswPalette) { + SelectPalette( b->hDc, mswPalette, 0 ); + RealizePalette( b->hDc ); + } + b->wFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSX ); + b->hFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSY ); + b->DPI = 96.0; /*min( b->wFactor, b->hFactor );*/ + b->hWnd = hWnd; + SetROP2( b->hDc, R2_WHITE ); + Rectangle( b->hDc, 0, 0, b->w, b->h ); + if ( (b->option & BD_DIRECT) == 0 ) { + SetROP2( hDc, R2_WHITE ); + Rectangle( hDc, 0, 0, b->w, b->h ); + ReleaseDC( hWnd, hDc ); + } + break; + case WM_SIZE: + b = (wDraw_p)mswMapIndex( inx ); + ix = LOWORD( lParam ); + iy = HIWORD( lParam ); + b->w = ix+2; + b->h = iy+2; + if (b->hWnd) { + if ( b->option & BD_DIRECT ) { + } else { + hDc = GetDC( b->hWnd ); + b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); + DeleteObject(SelectObject( b->hDc, b->hBm )); + ReleaseDC( b->hWnd, hDc ); + SetROP2( b->hDc, R2_WHITE ); + Rectangle( b->hDc, 0, 0, b->w, b->h ); + } + } + /*if (b->drawResize) + b->drawResize( b, b->size );*/ + if (b->drawRepaint) + b->drawRepaint( b, b->data, 0, 0 ); + return 0; + case WM_MOUSEMOVE: + activeWnd = GetActiveWindow(); + focusWnd = GetFocus(); + if (focusWnd != hWnd) { + b = (wDraw_p)mswMapIndex( inx ); + if (!b) + break; + if ( !((wControl_p)b->parent) ) + break; + if ( ((wControl_p)b->parent)->hWnd != activeWnd ) + break; + } + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + if (message == WM_LBUTTONDOWN) + action = wActionLDown; + else if (message == WM_RBUTTONDOWN) + action = wActionRDown; + else if (message == WM_LBUTTONUP) + action = wActionLUp; + else if (message == WM_RBUTTONUP) + action = wActionRUp; + else { + if ( (wParam & MK_LBUTTON) != 0) + action = wActionLDrag; + else if ( (wParam & MK_RBUTTON) != 0) + action = wActionRDrag; + else + action = wActionMove; + } + b = (wDraw_p)mswMapIndex( inx ); + if (!b) + break; + if (doSetFocus && message != WM_MOUSEMOVE) + SetFocus( ((wControl_p)b->parent)->hWnd ); + if ( (b->option&BD_NOCAPTURE) == 0 ) { + if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN) + SetCapture( b->hWnd ); + else if (message == WM_LBUTTONUP || message == WM_RBUTTONUP) + ReleaseCapture(); + } + ix = LOWORD( lParam ); + iy = HIWORD( lParam ); + x = XPIX2INCH( b, ix ); + y = YPIX2INCH( b, iy ); + if (b->action) + b->action( b, b->data, action, x, y ); + if (b->hWnd) + UpdateWindow(b->hWnd); + return 0; + case WM_CHAR: + b = (wDraw_p)mswMapIndex( inx ); + extChar = wAccelKey_None; + if (lParam & 0x01000000L) + switch( wParam ) { + case VK_DELETE: extChar = wAccelKey_Del; break; + case VK_INSERT: extChar = wAccelKey_Ins; break; + case VK_HOME: extChar = wAccelKey_Home; break; + case VK_END: extChar = wAccelKey_End; break; + case VK_PRIOR: extChar = wAccelKey_Pgup; break; + case VK_NEXT: extChar = wAccelKey_Pgdn; break; + case VK_UP: extChar = wAccelKey_Up; break; + case VK_DOWN: extChar = wAccelKey_Down; break; + case VK_RIGHT: extChar = wAccelKey_Right; break; + case VK_LEFT: extChar = wAccelKey_Left; break; + case VK_BACK: extChar = wAccelKey_Back; break; + /*case VK_F1: extChar = wAccelKey_F1; break;*/ + case VK_F2: extChar = wAccelKey_F2; break; + case VK_F3: extChar = wAccelKey_F3; break; + case VK_F4: extChar = wAccelKey_F4; break; + case VK_F5: extChar = wAccelKey_F5; break; + case VK_F6: extChar = wAccelKey_F6; break; + case VK_F7: extChar = wAccelKey_F7; break; + case VK_F8: extChar = wAccelKey_F8; break; + case VK_F9: extChar = wAccelKey_F9; break; + case VK_F10: extChar = wAccelKey_F10; break; + case VK_F11: extChar = wAccelKey_F11; break; + case VK_F12: extChar = wAccelKey_F12; break; + } + if (b && b->action) { + if (extChar != wAccelKey_None) + b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), 0, 0 ); + else + b->action( b, b->data, wActionText + ( wParam << 8 ), 0, 0 ); + } + return 0; + + case WM_PAINT: + b = (wDraw_p)mswMapIndex( inx ); + if (b && b->type == B_DRAW) { + if (GetUpdateRect( b->hWnd, &rect, FALSE )) { + hDc = BeginPaint( hWnd, &ps ); + if ( b->hasPalette ) { + int winPaletteClock = mswGetPaletteClock(); + if ( b->paletteClock < winPaletteClock ) { + RealizePalette( hDc ); + b->paletteClock = winPaletteClock; + } + } + BitBlt( hDc, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, + b->hDc, rect.left, rect.top, + SRCCOPY ); + EndPaint( hWnd, &ps ); + } + } + break; + case WM_DESTROY: + b = (wDraw_p)mswMapIndex( inx ); + if (b && b->type == B_DRAW) { + if (b->hDc) { + DeleteDC( b->hDc ); + b->hDc = (HDC)0; + } + if (b->hDcBackup) { + DeleteDC( b->hDcBackup ); + b->hDcBackup = (HDC)0; + } + } + break; + default: + break; + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static LRESULT drawMsgProc( wDraw_p b, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + wAction_t action; + + switch( message ) { + case WM_MOUSEWHEEL: + /* handle mouse wheel events */ + /* fwKeys = GET_KEYSTATE_WPARAM(wParam); modifier keys are currently ignored */ + if ( GET_WHEEL_DELTA_WPARAM(wParam) > 0 ) { + action = wActionWheelUp; + } else { + action = wActionWheelDown; + } + if (b->action) + b->action( b, b->data, action, 0, 0 ); + return 0; + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static void drawDoneProc( wControl_p b ) +{ + wDraw_p d = (wDraw_p)b; + if (d->hBm) { + SelectObject( d->hDc, d->hBmOld ); + DeleteObject( d->hBm ); + d->hBm = (HBITMAP)0; + } + if (d->hPen) { + SelectObject( d->hDc, GetStockObject( BLACK_PEN ) ); + DeleteObject( d->hPen ); + d->hPen = (HPEN)0; + } + if (d->hBrush) { + SelectObject( d->hDc, GetStockObject( BLACK_BRUSH) ); + DeleteObject( d->hBrush ); + d->hBrush = (HBRUSH)0; + } + if (d->hDc) { + DeleteDC( d->hDc ); + d->hDc = (HDC)0; + } + if ( d->hDcBackup ) { + DeleteDC( d->hDcBackup ); + d->hDcBackup = (HDC)0; + } + while (bmRoot) { + if (bmRoot->bm) + DeleteObject( bmRoot->bm ); + bmRoot = bmRoot->next; + } +} + + +static callBacks_t drawCallBacks = { + NULL, + drawDoneProc, + (messageCallback_p)drawMsgProc }; + +wDraw_p drawList = NULL; + + +void mswRedrawAll( void ) +{ + wDraw_p p; + for ( p=drawList; p; p=p->drawNext ) { + if (p->drawRepaint) + p->drawRepaint( p, p->data, 0, 0 ); + } +} + + +void mswRepaintAll( void ) +{ + wDraw_p b; + HDC hDc; + RECT rect; + PAINTSTRUCT ps; + + for ( b=drawList; b; b=b->drawNext ) { + if (GetUpdateRect( b->hWnd, &rect, FALSE )) { + hDc = BeginPaint( b->hWnd, &ps ); + BitBlt( hDc, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, + b->hDc, rect.left, rect.top, + SRCCOPY ); + EndPaint( b->hWnd, &ps ); + } + } +} + + +wDraw_p wDrawCreate( + wWin_p parent, + wPos_t x, + wPos_t y, + const char * helpStr, + long option, + wPos_t w, + wPos_t h, + void * data, + wDrawRedrawCallBack_p redrawProc, + wDrawActionCallBack_p action ) +{ + wDraw_p d; + RECT rect; + int index; + HDC hDc; + + if ( noNegDrawArgs < 0 ) { + wPrefGetInteger( "msw tweak", "NoNegDrawArgs", &noNegDrawArgs, 0 ); + wPrefGetInteger( "msw tweak", "NoFlatEndCaps", &noFlatEndCaps, 0 ); + } + + d = mswAlloc( parent, B_DRAW, NULL, sizeof *d, data, &index ); + mswComputePos( (wControl_p)d, x, y ); + d->w = w; + d->h = h; + d->drawRepaint = NULL; + d->action = action; + d->option = option; + + d->hWnd = CreateWindow( mswDrawWindowClassName, NULL, + WS_CHILDWINDOW|WS_VISIBLE|WS_BORDER, + d->x, d->y, w, h, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + + if (d->hWnd == (HWND)0) { + mswFail( "CreateWindow(DRAW)" ); + return d; + } + + GetWindowRect( d->hWnd, &rect ); + + d->w = rect.right - rect.left; + d->h = rect.bottom - rect.top; + d->drawRepaint = redrawProc; + /*if (d->drawRepaint) + d->drawRepaint( d, d->data, 0.0, 0.0 );*/ + + mswAddButton( (wControl_p)d, FALSE, helpStr ); + mswCallBacks[B_DRAW] = &drawCallBacks; + d->drawNext = drawList; + drawList = d; + if (mswPalette) { + hDc = GetDC( d->hWnd ); + d->hasPalette = TRUE; + SelectPalette( hDc, mswPalette, 0 ); + ReleaseDC( d->hWnd, hDc ); + } + return d; +} + +/* + ***************************************************************************** + * + * Bitmaps + * + ***************************************************************************** + */ + +wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes ) +{ + wDraw_p d; + HDC hDc; + + d = (wDraw_p)calloc(1,sizeof *d); + d->type = B_DRAW; + d->shown = TRUE; + d->x = 0; + d->y = 0; + d->w = w; + d->h = h; + d->drawRepaint = NULL; + d->action = NULL; + d->option = 0; + + hDc = GetDC(mswHWnd); + d->hDc = CreateCompatibleDC( hDc ); + if ( d->hDc == (HDC)0 ) { + wNoticeEx( NT_ERROR, "CreateBitMap: CreateDC fails", "Ok", NULL ); + return FALSE; + } + d->hBm = CreateCompatibleBitmap( hDc, d->w, d->h ); + if ( d->hBm == (HBITMAP)0 ) { + wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM fails", "Ok", NULL ); + return FALSE; + } + d->hasPalette = (GetDeviceCaps(hDc,RASTERCAPS ) & RC_PALETTE) != 0; + ReleaseDC( mswHWnd, hDc ); + d->hBmOld = SelectObject( d->hDc, d->hBm ); + if (mswPalette) { + SelectPalette( d->hDc, mswPalette, 0 ); + RealizePalette( d->hDc ); + } + d->wFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSX ); + d->hFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSY ); + d->DPI = 96.0; /*min( d->wFactor, d->hFactor );*/ + d->hWnd = 0; + SetROP2( d->hDc, R2_WHITE ); + Rectangle( d->hDc, 0, 0, d->w, d->h ); + return d; +} + +wBool_t wBitMapDelete( wDraw_p d ) +{ + if (d->hPen) { + SelectObject( d->hDc, GetStockObject( BLACK_PEN ) ); + DeleteObject( d->hPen ); + d->hPen = (HPEN)0; + } + if (d->hBm) { + SelectObject( d->hDc, d->hBmOld ); + DeleteObject( d->hBm ); + d->hBm = (HBITMAP)0; + } + if (d->hDc) { + DeleteDC( d->hDc ); + d->hDc = (HDC)0; + } + free(d); + return TRUE; +} + +wBool_t wBitMapWriteFile( wDraw_p d, const char * fileName ) +{ + char *pixels; + int j, ww, chunk; + FILE * f; + BITMAPFILEHEADER bmfh; + struct { + BITMAPINFOHEADER bmih; + RGBQUAD colors[256]; + } bmi; + int rc; + + if ( d->hBm == 0) + return FALSE; + f = wFileOpen( fileName, "wb" ); + if (!f) { + wNoticeEx( NT_ERROR, fileName, "Ok", NULL ); + return FALSE; + } + ww = ((d->w +3) / 4) * 4; + bmfh.bfType = 'B'+('M'<<8); + bmfh.bfSize = (long)(sizeof bmfh) + (long)(sizeof bmi.bmih) + (long)(sizeof bmi.colors) + (long)ww * (long)(d->h); + bmfh.bfReserved1 = 0; + bmfh.bfReserved2 = 0; + bmfh.bfOffBits = sizeof bmfh + sizeof bmi.bmih + sizeof bmi.colors; + fwrite( &bmfh, 1, sizeof bmfh, f ); + bmi.bmih.biSize = sizeof bmi.bmih; + bmi.bmih.biWidth = d->w; + bmi.bmih.biHeight = d->h; + bmi.bmih.biPlanes = 1; + bmi.bmih.biBitCount = 8; + bmi.bmih.biCompression = BI_RGB; + bmi.bmih.biSizeImage = 0; + bmi.bmih.biXPelsPerMeter = 75*(10000/254); + bmi.bmih.biYPelsPerMeter = 75*(10000/254); + bmi.bmih.biClrUsed = bmi.bmih.biClrImportant = mswGetColorList( bmi.colors ); + SelectObject( d->hDc, d->hBmOld ); + rc = GetDIBits( d->hDc, d->hBm, 0, 1, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS ); + if ( rc == 0 ) { + wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bitmapinfo from Bitmap", "Ok", NULL ); + return FALSE; + } + bmi.bmih.biClrUsed = 256; + fwrite( &bmi.bmih, 1, sizeof bmi.bmih, f ); + fwrite( bmi.colors, 1, sizeof bmi.colors, f ); + chunk = 32000/ww; + pixels = (char*)malloc( ww*chunk ); + if ( pixels == NULL ) { + wNoticeEx( NT_ERROR, "WriteBitMap: no memory", "OK", NULL ); + return FALSE; + } + for (j=0;j<d->h;j+=chunk) { + if (j+chunk>d->h) + chunk = d->h-j; + rc = GetDIBits( d->hDc, d->hBm, j, chunk, pixels, (BITMAPINFO*)&bmi, DIB_RGB_COLORS ); + if ( rc == 0 ) + if ( rc == 0 ) { + wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bits from Bitmap", "Ok", NULL ); + return FALSE; + } + rc = fwrite( pixels, 1, ww*chunk, f ); + if (rc != ww*chunk) { + wNoticeEx( NT_ERROR, "WriteBitMap: Bad fwrite", "Ok", NULL); + } + } + free( pixels ); + SelectObject( d->hDc, d->hBm ); + fclose( f ); + return TRUE; +} + |