summaryrefslogtreecommitdiff
path: root/app/wlib/mswlib/mswdraw.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/wlib/mswlib/mswdraw.c')
-rw-r--r--app/wlib/mswlib/mswdraw.c1783
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 &timesFont[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;
+}
+