diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-22 14:05:41 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-22 14:05:41 +0200 | 
| commit | b55285a77da0e0b829e4ce8d7e09debaabc68e15 (patch) | |
| tree | f622559ef65bbdd3e1c5bdb06098a8f89eec0563 /app/wlib/mswlib | |
| parent | d3897ce090dbeb220ed2c782f095597e417cf3cc (diff) | |
| parent | d1ae75703e1ed81d65ea16946dcdb77e7a13adc9 (diff) | |
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'app/wlib/mswlib')
| -rw-r--r-- | app/wlib/mswlib/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | app/wlib/mswlib/backgnd.c | 220 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswbitmap.c | 46 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswbutt.c | 21 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswchksm.c | 125 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswdraw.c | 833 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswedit.c | 210 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswint.h | 23 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswlist.c | 2 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswmenu.c | 8 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswmisc.c | 266 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswmsg.c | 9 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswpref.c | 1 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswprint.c | 46 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswsplash.c | 8 | ||||
| -rw-r--r-- | app/wlib/mswlib/mswtext.c | 63 | ||||
| -rw-r--r-- | app/wlib/mswlib/simple-gettext.c | 3 | ||||
| -rw-r--r-- | app/wlib/mswlib/unittest/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | app/wlib/mswlib/unittest/utf8test.c | 65 | ||||
| -rw-r--r-- | app/wlib/mswlib/utf8conv.c | 210 | 
20 files changed, 1547 insertions, 642 deletions
| diff --git a/app/wlib/mswlib/CMakeLists.txt b/app/wlib/mswlib/CMakeLists.txt index 82d8371..07558f9 100644 --- a/app/wlib/mswlib/CMakeLists.txt +++ b/app/wlib/mswlib/CMakeLists.txt @@ -1,12 +1,13 @@ +find_package(FreeImage REQUIRED) +  FILE(GLOB HEADERS *.h)  SET(SOURCES -#	checksum.c +	backgnd.c  	getopt.c  	mswbox.c  	mswbutt.c  	mswbitmap.c -	mswchksm.c  	mswchoic.c  	mswcolor.c  	mswdraw.c @@ -19,14 +20,15 @@ SET(SOURCES  	mswpref.c  	mswprint.c  	mswsplash.c -	mswstatus.c  +	mswstatus.c  	mswtext.c  	gwin32.c  	simple-gettext.c +	utf8conv.c  	) +include_directories(${FREEIMAGE_INCLUDE_PATH})  INCLUDE_DIRECTORIES(${XTrkCAD_BINARY_DIR}) -# INCLUDE_DIRECTORIES(${XTRKCAD_BINARY_DIR})  IF(XTRKCAD_USE_GETTEXT)  	IF(WIN32) @@ -37,4 +39,13 @@ ENDIF(XTRKCAD_USE_GETTEXT)  ADD_LIBRARY(xtrkcad-wlib ${HEADERS} ${SOURCES})  TARGET_LINK_LIBRARIES(xtrkcad-wlib Htmlhelp msimg32 shlwapi) +target_link_libraries(xtrkcad-wlib ${FREEIMAGE_LIBRARY}) + +install(FILES +	${FREEIMAGE_SHAREDLIB} +	DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} +	) +if(XTRKCAD_TESTING AND CMOCKA_FOUND) +	add_subdirectory( unittest ) +endif() diff --git a/app/wlib/mswlib/backgnd.c b/app/wlib/mswlib/backgnd.c new file mode 100644 index 0000000..d35f19a --- /dev/null +++ b/app/wlib/mswlib/backgnd.c @@ -0,0 +1,220 @@ +/** \file backgnd.c +* Layout background image +*/ + +/*  XTrkCad - Model Railroad CAD +*  Copyright (C) 2018 Martin Fischer +* +*  This program is free software; you can redistribute it and/or modify +*  it under the terms of the GNU General Public License as published by +*  the Free Software Foundation; either version 2 of the License, or +*  (at your option) any later version. +* +*  This program is distributed in the hope that it will be useful, +*  but WITHOUT ANY WARRANTY; without even the implied warranty of +*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +*  GNU General Public License for more details. +* +*  You should have received a copy of the GNU General Public License +*  along with this program; if not, write to the Free Software +*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <windows.h> + +#include <FreeImage.h> +#include "i18n.h" +#include "mswint.h" + +static char *lastErrorMessage;		/**< store last message from FreeImage */ +#define ERRORPUNCTUATION " : " + +/**
 + * FreeImage error handler
 + * \param fif Format / Plugin responsible for the error
 + * \param message Error message
 + */ + +static void 
 +HandleFreeImageError(FREE_IMAGE_FORMAT fif, const char *message) 
 +{
 +	unsigned totalLength = strlen(message) + 1;
 +
 +	if (fif != FIF_UNKNOWN) {
 +		totalLength += strlen(FreeImage_GetFormatFromFIF(fif)) + strlen(ERRORPUNCTUATION);
 +	}
 +
 +	lastErrorMessage = malloc(totalLength);
 +
 +	if (fif != FIF_UNKNOWN) {
 +		sprintf(lastErrorMessage,
 +				"%s" ERRORPUNCTUATION "%s",
 +				FreeImage_GetFormatFromFIF(fif),
 +				message);
 +	} else {
 +		strcpy(lastErrorMessage, message);
 +	}
 +} + +/**
 +* Load the background image
 +* \param bd drawing context
 +* \param path filename for image file, if NULL the existing background will be removed
 +* \param error returned error message
 +* \return -1 unsupported or invalid file, 0 success, 1 background removed
 +*/ + +int +wDrawSetBackground(wDraw_p bd, char * path, char ** error) +{ +    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; + +	FreeImage_SetOutputMessage(HandleFreeImageError); +
 +	if (lastErrorMessage) {
 +		free(lastErrorMessage);
 +		lastErrorMessage = NULL;
 +	} + +    if (path) { +        // check the file signature and deduce its format +        // (the second argument is currently not used by FreeImage) +        fif = FreeImage_GetFileType(path, 0); + +        if (fif == FIF_UNKNOWN) { +            // no signature ? +            // try to guess the file format from the file extension +            fif = FreeImage_GetFIFFromFilename(path); +        } + +        // check that the plugin has reading capabilities ... +        if ((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { +            // ok, let's load the file +            bd->background = FreeImage_Load(fif, path, 0); + +            // unless a bad file format, we are done ! +            if (!bd->background) { +                *error = lastErrorMessage; +                return (-1); +            } else { +                return (0); +            } +        } else { +			*error = strdup(_("Image file is invalid or cannot be read.")); +            return (-1); +        } +    } else { +        if (bd->background) { +            FreeImage_Unload(bd->background); +            bd->background = 0; +        } + +        return (1); +    } +} + +/**
 +* Draw background to screen. The background will be sized and rotated before being shown. The bitmap 
 +* is scaled so that the width is equal to size. The height is changed proportionally. 
 +*
 +* \param bd drawing context
 +* \param pos_x, pos_y bitmap position
 +* \param size desired width after scaling
 +* \param angle 
 +* \param screen visibility of bitmap in percent
 +*/ + +void +wDrawShowBackground(wDraw_p bd, wPos_t pos_x, wPos_t pos_y, wPos_t size, +                    wAngle_t angle, int screen) +{ +    if (bd->background) { +        double scale; +        FIBITMAP *tmp; +        FIBITMAP *rotated; + +        if (size == 0) { +            scale = 1.0; +        } else { +            scale = (double)size / FreeImage_GetWidth(bd->background); +        } + +        tmp = FreeImage_RescaleRect(bd->background, +                                    (int)((double)FreeImage_GetWidth(bd->background) * scale), +                                    (int)((double)FreeImage_GetHeight(bd->background) * scale), +                                    0, +                                    0, +                                    FreeImage_GetWidth(bd->background), +                                    FreeImage_GetHeight(bd->background), +                                    FILTER_BILINEAR, +                                    0); +        FreeImage_AdjustColors(tmp, screen, -screen, 1.0, FALSE); +        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(tmp); + +        switch (image_type) { +        case FIT_BITMAP: +            switch (FreeImage_GetBPP(tmp)) { +            case 8: { +                BYTE color = 255; +                rotated = FreeImage_Rotate(tmp, angle, &color); +            } +            break; + +            case 24: // we could also use 'RGBTRIPLE color' here +            case 32: { +                RGBQUAD color = { 255, 255, 255, 0 }; +                // for 24-bit images, the first 3 bytes will be read +                // for 32-bit images, the first 4 bytes will be read +                rotated = FreeImage_Rotate(tmp, angle, &color); +            } +            break; +            } + +            break; + +        case FIT_UINT16: { +            WORD color = 255; +            rotated = FreeImage_Rotate(tmp, angle, &color); +        } +        break; + +        case FIT_RGB16: // we could also use 'FIRGB16 color' here +        case FIT_RGBA16: { +            FIRGBA16 color = { 255, 255, 255, 0 }; +            // for RGB16 images, the first 3 WORD will be read +            // for RGBA16 images, the first 4 WORD will be read +            rotated = FreeImage_Rotate(tmp, angle, &color); +        } +        break; + +        case FIT_FLOAT: { +            float color = 1.0F; +            rotated = FreeImage_Rotate(tmp, angle, &color); +        } +        break; + +        case FIT_RGBF: // we could also use 'FIRGBF color' here +        case FIT_RGBAF: { +            FIRGBAF color = { 1, 1, 1, 0 }; +            // for RGBF images, the first 3 float will be read +            // for RGBAF images, the first 4 float will be read +            rotated = FreeImage_Rotate(tmp, angle, &color); +        } +        break; +        } + +        SetDIBitsToDevice(bd->hDc, +                          pos_x, +                          bd->h - pos_y - FreeImage_GetHeight(rotated), +                          FreeImage_GetWidth(rotated), +                          FreeImage_GetHeight(rotated), +                          0, 0, +                          0, +                          FreeImage_GetHeight(rotated), +                          FreeImage_GetBits(rotated), +                          FreeImage_GetInfo(rotated), +                          DIB_RGB_COLORS); +        FreeImage_Unload(tmp); +        FreeImage_Unload(rotated); +    } +}
\ No newline at end of file diff --git a/app/wlib/mswlib/mswbitmap.c b/app/wlib/mswlib/mswbitmap.c index e369e78..95b8a69 100644 --- a/app/wlib/mswlib/mswbitmap.c +++ b/app/wlib/mswlib/mswbitmap.c @@ -24,10 +24,12 @@  #include <windows.h>  #include <string.h>  #include <malloc.h> +#include <math.h>  #include <stdlib.h>  #include <commdlg.h>  #include <stdio.h>  #include <assert.h> +#include "misc.h"  #include "mswint.h"  #include "i18n.h" @@ -177,14 +179,15 @@ void mswDrawIcon(  		memset( bmiInfo->bmiColors, 0, bm->colorcnt * sizeof( RGBQUAD ));  		memset( &bmiInfo->bmiColors[ bm->transparent ], 0xFF, sizeof( RGBQUAD ));  	} +  	StretchDIBits(hDc, offw, offh, -        bmiInfo->bmiHeader.biWidth, -        bmiInfo->bmiHeader.biHeight, -        0, 0, -        bmiInfo->bmiHeader.biWidth, -        bmiInfo->bmiHeader.biHeight, -        bm->pixels, bmiInfo, 				 -        DIB_RGB_COLORS, SRCAND); +				 (int)ceil(bmiInfo->bmiHeader.biWidth*scaleIcon), +	             (int)ceil(bmiInfo->bmiHeader.biHeight*scaleIcon), +	              0, 0, +	              bmiInfo->bmiHeader.biWidth, +	              bmiInfo->bmiHeader.biHeight, +	              bm->pixels, bmiInfo, +	              DIB_RGB_COLORS, SRCAND);  	/* now paint the bitmap with transparent set to black */  	if( bm->type == mswIcon_bitmap ) { @@ -221,16 +224,16 @@ void mswDrawIcon(          }  		memset( &bmiInfo->bmiColors[ bm->transparent ], 0, sizeof( RGBQUAD ));      } -     +      /* show the bitmap */      StretchDIBits(hDc, offw, offh, -            bmiInfo->bmiHeader.biWidth, -            bmiInfo->bmiHeader.biHeight, -            0, 0, -            bmiInfo->bmiHeader.biWidth, -            bmiInfo->bmiHeader.biHeight, -            bm->pixels, bmiInfo, 				 -            DIB_RGB_COLORS, SRCPAINT); +				 (int)ceil(bmiInfo->bmiHeader.biWidth*scaleIcon), +	             (int)ceil(bmiInfo->bmiHeader.biHeight*scaleIcon), +                  0, 0, +                  bmiInfo->bmiHeader.biWidth, +                  bmiInfo->bmiHeader.biHeight, +                  bm->pixels, bmiInfo, +                  DIB_RGB_COLORS, SRCPAINT);      /* forget the data */      free( bmiInfo ); @@ -434,11 +437,14 @@ wIcon_p wIconCreatePixMap( char *pm[])  			/* look up pixel info in color table */  			k = 0; -			while( pixel != keys[ k ] ) +			while(k < col && pixel != keys[ k ] )  				k++; - -			/* save the index into color table */ -			*(cq + j) = k; +			if (pixel == keys[k]) { +				/* save the index into color table */ +				*(cq + j) = k; +			} else { +				*(cq + j) = 0; +			}  		}  	}		  	free( keys ); @@ -507,4 +513,4 @@ wBitmapCreate( wWin_p parent, wPos_t x, wPos_t y, long option, wIcon_p iconP )  	control->data = iconP;  	return (wControl_p)control; -}
\ No newline at end of file +} diff --git a/app/wlib/mswlib/mswbutt.c b/app/wlib/mswlib/mswbutt.c index d213695..16f31c1 100644 --- a/app/wlib/mswlib/mswbutt.c +++ b/app/wlib/mswlib/mswbutt.c @@ -37,11 +37,7 @@ int kludge12 = 0;   *****************************************************************************   */ - -  static XWNDPROC oldButtProc = NULL; -static XWNDPROC newButtProc; -  struct wButton_t {  		WOBJ_COMMON @@ -88,9 +84,9 @@ static void drawButton(  	COLORREF colF;  #define LEFT (0) -#define RIGHT (bm->w+10) +#define RIGHT (LONG)ceil(bm->w*scaleIcon+10)  #define TOP (0) -#define BOTTOM (bm->h+10) +#define BOTTOM (LONG)ceil(bm->h*scaleIcon+10)  	/* get the lightest and the darkest color to use */  	colL = GetSysColor( COLOR_BTNHIGHLIGHT ); @@ -239,6 +235,7 @@ static LRESULT buttPush( wControl_p b, HWND hWnd, UINT message, WPARAM wParam, L  	DRAWITEMSTRUCT * di = (DRAWITEMSTRUCT *)lParam;  	wBool_t selected; +  	switch (message) {  	case WM_COMMAND:  		if (bb->action /*&& !bb->busy*/) { @@ -253,8 +250,8 @@ static LRESULT buttPush( wControl_p b, HWND hWnd, UINT message, WPARAM wParam, L  			break;  		mi->CtlType = ODT_BUTTON;  		mi->CtlID = wParam; -		mi->itemWidth = bb->w; -		mi->itemHeight = bb->h; +		mi->itemWidth = (UINT)ceil(bb->w*scaleIcon); +		mi->itemHeight = (UINT)ceil(bb->h*scaleIcon);  		} return 0L;  	case WM_DRAWITEM: @@ -369,8 +366,8 @@ wButton_p wButtonCreate(  	b->selected = 0;  	mswComputePos( (wControl_p)b, x, y );  	if (b->option&BO_ICON) { -		width = bm->w+10; -		h = bm->h+10; +		width = (wPos_t)ceil(bm->w*scaleIcon)+10; +		h = (int)ceil(bm->h*scaleIcon)+10;  		b->icon = bm;  	} else {  		width = (wPos_t)(width*mswScale); @@ -405,5 +402,9 @@ wButton_p wButtonCreate(  	}  	if ( !mswThickFont )  		SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + + +	InvalidateRect(b->hWnd, &rect, TRUE); +  	return b;  } diff --git a/app/wlib/mswlib/mswchksm.c b/app/wlib/mswlib/mswchksm.c deleted file mode 100644 index 602c204..0000000 --- a/app/wlib/mswlib/mswchksm.c +++ /dev/null @@ -1,125 +0,0 @@ -#include <stdio.h> -#include <sys/stat.h> -#include "../include/wlib.h" -#ifdef WINDOWS -#include <windows.h> -#include "mswint.h" -#endif - -#define HEWHDROFFSET	(0x3C) - -static FILE * openfile( const char * fn, const char * mode, long * fileSize ) -{ -	unsigned short PageCnt; -	long FileSize; -	FILE *fp; -	struct stat Stat; -	fp = fopen( fn, mode ); -	if (fp == NULL) { -		perror( "fopen" ); -		return NULL; -	} -	fread( &PageCnt, sizeof(PageCnt), 1, fp ); /* Read past signature */ -	fread( &PageCnt, sizeof(PageCnt), 1, fp ); /* Read past pagesize */ -	FileSize = PageCnt; -	fread( &PageCnt, sizeof(PageCnt), 1, fp ); /* Read past pagesize */ -	if ( FileSize == 0L ) -		FileSize = PageCnt * 512L; -	else -		FileSize += (PageCnt - 1) * 512L; -	*fileSize = FileSize; -	stat( fn, &Stat ); -	*fileSize = (long)Stat.st_size; -	fprintf( stderr, "size1 = %ld, size2 = %ld\n", FileSize, (long)Stat.st_size ); -	return fp; -} - - -static unsigned short mswCheck16( FILE * fp, long FileSize, unsigned short * sum16stored ) -{ -	unsigned short int sum16, NxtInt; -	long x; -	unsigned char NxtChar; -	sum16 = 0; -	fseek(fp, 0, SEEK_SET); - -	for (x=0L; x<FileSize/2L; x++) { -		fread( &NxtInt, sizeof NxtInt, 1, fp ); -		if (x == 9) -			*sum16stored = NxtInt; -		else -			sum16 += NxtInt; -	} -	if (FileSize%2) { -		fread( &NxtChar, sizeof NxtChar, 1, fp ); -		sum16 += (unsigned int)NxtChar; -	} -	return sum16; -} - - -static int mswCheck32( FILE * fp, long FileSize, long * sum32off, unsigned long * sum32computed, unsigned long * sum32stored ) -{ -	unsigned long sum32, NxtLong; -	long x; -	long NewHdrOffset; -	unsigned char NxtByte, y; - -	fseek( fp, HEWHDROFFSET, SEEK_SET ); -	fread( &NewHdrOffset, sizeof NewHdrOffset, 1, fp ); -	if (NewHdrOffset == 0) { -		fprintf( stderr, "NewHdrOffset == 0\n" ); -		return 0; -	} -	NewHdrOffset = (NewHdrOffset/4)*4; -	*sum32off = NewHdrOffset + 8; -	sum32 = 0L; -	fseek( fp, 0, SEEK_SET ); -	for (x = ( NewHdrOffset + 8 ) / 4; x; x-- ) { -		fread( &NxtLong, sizeof NxtLong, 1, fp ); -		sum32 += NxtLong; -	} -	fread( sum32stored, sizeof sum32stored, 1, fp ); - -	for (x=0; x<(FileSize-NewHdrOffset - 12)/4; x++) { -		fread( &NxtLong, sizeof NxtLong, 1, fp ); -		sum32 += NxtLong; -	} -	if ( 0L != (x=FileSize%4L) ) { -		NxtLong = 0L; -		for (y=0; y<x; y++ ) { -			fread( &NxtByte, sizeof NxtByte, 1, fp ); -			NxtLong += (unsigned long)NxtByte << (8*y); -		} -		sum32 += NxtLong; -	} -	*sum32computed = sum32; -	return 1; -} - - -#ifdef WINDOWS -wBool_t wCheckExecutable( void ) -{ -	char fileName[1024]; -	FILE * fp; -	long FileSize; -	GetModuleFileName( mswHInst, fileName, sizeof fileName ); -	fp = openfile( fileName, "rb", &FileSize ); -#ifdef LATER -	{ -		unsigned long int sum32offset, sum32computed, sum32stored; -		if ( ! mswCheck32( fp, FileSize, &sum32offset, &sum32computed, &sum32stored ) ) -			return FALSE; -		return sum32computed == sum32stored; -	} -#else -	{ -		unsigned short int sum16computed, sum16stored; -		sum16computed = mswCheck16( fp, FileSize, &sum16stored ); -		sum16computed += sum16stored; -		return sum16computed == 0xFFFF; -	} -#endif -} -#endif diff --git a/app/wlib/mswlib/mswdraw.c b/app/wlib/mswlib/mswdraw.c index bf0ab76..c2739e6 100644 --- a/app/wlib/mswlib/mswdraw.c +++ b/app/wlib/mswlib/mswdraw.c @@ -1,8 +1,26 @@ -/* - * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswdraw.c,v 1.6 2009-05-15 18:16:16 m_fischer Exp $ +/** \file mswdraw.c + * Draw basic geometric shapes   */ -#define _WIN32_WINNT 0x0500		/* for wheel mouse supposrt */ +/*  XTrackCAD - Model Railroad CAD + *  Copyright (C) 2005 Dave Bullis + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */	 + +#define _WIN32_WINNT 0x0600		/* for wheel mouse supposrt */  #include <windows.h>  #include <string.h>  #include <malloc.h> @@ -16,8 +34,12 @@  #else  #define wFont_t tagLOGFONT  #endif + +#include "misc.h"  #include "mswint.h" +#include <FreeImage.h> +wBool_t wDrawDoTempDraw = TRUE;  /*   *****************************************************************************   * @@ -39,6 +61,8 @@ static long clrOp = 0xbb0226;  #define CENTERMARK_LENGTH 6 +bool bDrawMainBM = 0; +  #ifdef SLOW  static wPos_t XPIX2INCH( wDraw_p d, int ix )  { @@ -119,6 +143,31 @@ void wDrawDelayUpdate(  {  } +wBool_t wDrawSetTempMode( +	wDraw_p bd, +	wBool_t bTemp ) +{ +	wBool_t rc = bd->bTempMode; +	bd->bTempMode = bTemp; +	if (rc == FALSE && bTemp == TRUE) { +		// Main to Temp drawing +		// Copy mainBM to tempBM +		wDrawClearTemp( bd ); +		if (bDrawMainBM) return rc; +		HDC hDcOld = CreateCompatibleDC(bd->hDc); +		HBITMAP hBmOld = SelectObject(hDcOld, bd->hBmMain); +		SelectObject(bd->hDc, bd->hBmTemp); +		BitBlt(bd->hDc, 0, 0, +			bd->w, bd->h, +			hDcOld, 0, 0, +			SRCCOPY); +		SelectObject(hDcOld, hBmOld); +		DeleteDC(hDcOld); +		bd->bCopiedMain = TRUE; +	} +	return rc; +} +  /**   * Sets the proper pen and composition for the next drawing operation   *  @@ -130,68 +179,83 @@ void wDrawDelayUpdate(   * \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; +	long centerPen[] = {40,10,20,10}; +	long phantomPen[] = {40,10,20,10,20,10}; +  	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 ( wDrawDoTempDraw && (dopt & wDrawOptTemp) ) +		SelectObject(d->hDc, d->hBmTemp); +	else +		SelectObject(d->hDc, d->hBmMain); +  	if ( d->hasPalette ) {  		int winPaletteClock = mswGetPaletteClock();  		if ( d->paletteClock < winPaletteClock ) { -			RealizePalette( hDc ); +			RealizePalette( d->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 ) +	SetROP2( d->hDc, R2_COPYPEN ); +	if ( d == d0 && 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; +	d0 = d; dw0 = dw; lt0 = lt; dc0 = dc; + +	void * penarray = NULL; +	int penarray_size = 0;  	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 ); +	} else if (lt == wDrawLineDot) { +		penStyle = PS_GEOMETRIC | PS_DOT; +	} else if (lt == wDrawLineDash) { +		penStyle = PS_GEOMETRIC | PS_DASH; +	} else if (lt == wDrawLineDashDot) { +		penStyle = PS_GEOMETRIC | PS_DASHDOT; +	} else if ( lt == wDrawLineDashDotDot){ +		penStyle = PS_GEOMETRIC | PS_DASHDOTDOT; +	} else if (  lt == wDrawLineCenter) { +		penStyle = PS_GEOMETRIC | PS_USERSTYLE; +		penarray = ¢erPen; +		penarray_size = sizeof(centerPen)/sizeof(long); +	} else if (  lt == wDrawLinePhantom) { +		penStyle = PS_GEOMETRIC | PS_USERSTYLE; +		penarray = &phantomPen; +		penarray_size = sizeof(phantomPen) / sizeof(long); +	} else +		penStyle = PS_GEOMETRIC | PS_SOLID; +	d->hPen = ExtCreatePen( penStyle, +					dw, +					&logBrush, +					penarray_size, +					penarray ); +	hOldPen = SelectObject( d->hDc, d->hPen );  	DeleteObject( hOldPen );  }  static void setDrawBrush( -		HDC hDc,  		wDraw_p d,  		wDrawColor dc,  		wDrawOpts dopt ) @@ -200,7 +264,7 @@ static void setDrawBrush(  	static wDraw_p d0;  	static wDrawColor dc0 = -1; -	setDrawMode( hDc, d, 0, wDrawLineSolid, dc, dopt ); +	setDrawMode( d, 0, wDrawLineSolid, dc, dopt );  	if ( d == d0 && dc == dc0 )  		return; @@ -208,7 +272,7 @@ static void setDrawBrush(  	d->hBrush = CreateSolidBrush(   				mswGetColor(d->hasPalette,dc) ); -	hOldBrush = SelectObject( hDc, d->hBrush ); +	hOldBrush = SelectObject( d->hDc, d->hBrush );  	DeleteObject( hOldBrush );  } @@ -270,7 +334,7 @@ void wDrawLine(  {  	POINT p0, p1;  	RECT rect; -	setDrawMode( d->hDc, d, dw, lt, dc, dopt ); +	setDrawMode( d, dw, lt, dc, dopt );  	p0.x = XINCH2PIX(d,p0x);  	p0.y = YINCH2PIX(d,p0y);  	p1.x = XINCH2PIX(d,p1x); @@ -381,7 +445,7 @@ void wDrawArc(  	pe.x = XINCH2PIX(d,(wPos_t)pex);  	pe.y = YINCH2PIX(d,(wPos_t)pey); -	setDrawMode( d->hDc, d, dw, lt, dc, dopt ); +	setDrawMode( d, dw, lt, dc, dopt );  	if (dw == 0)  		dw = 1; @@ -495,7 +559,7 @@ void wDrawPoint(  		return;  	if ( p0.x >= d->w || p0.y >= d->h )  		return; -	setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt ); +	setDrawMode( d, 0, wDrawLineSolid, dc, dopt );  	SetPixel( d->hDc, p0.x, p0.y, mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/ );  	if (d->hWnd) { @@ -689,6 +753,7 @@ void wDrawGetTextSize(  		wPos_t *w,  		wPos_t *h,  		wPos_t *d, +		wPos_t *a,  		wDraw_p bd,  		const char * text,  		wFont_p fp, @@ -717,12 +782,25 @@ void wDrawGetTextSize(  	*w = XPIXELSTOINCH( bd, x );  	*h = YPIXELSTOINCH( bd, y );  	*d = YPIXELSTOINCH(bd, textMetric.tmDescent ); +	*a = YPIXELSTOINCH(bd, textMetric.tmAscent );  	SelectObject( bd->hDc, prevFont );  	DeleteObject( newFont );  	fp->lfHeight = oldLfHeight;  } - +/** + * Draw text + *  + * \param d	device context + * \param px position x + * \param py position y + * \param angle drawing angle + * \param text text to print + * \param fp font + * \param siz font size + * \param dc color + * \param dopts drawing options + */  void wDrawString(      wDraw_p d,      wPos_t px, @@ -736,8 +814,6 @@ void wDrawString(  {      int x, y;      HFONT newFont, prevFont; -    HDC newDc; -    HBITMAP oldBm, newBm;      DWORD extent;      int w, h;      RECT rect; @@ -756,61 +832,47 @@ void wDrawString(      y = YINCH2PIX(d,py) + (int)(mswcos(angle)*fp->lfHeight-0.5);      if (noNegDrawArgs > 0 && (x < 0 || y < 0)) { +		DeleteObject(newFont);          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); +		setDrawMode( d, 0, wDrawLineSolid, dc, dopts ); +		prevFont = SelectObject(d->hDc, newFont); +        SetBkMode(d->hDc, TRANSPARENT); -        if (h > w) { -            w = h; +        if (dopts & wDrawOutlineFont) { +            HPEN oldPen; +            BeginPath(d->hDc); +            TextOut(d->hDc, x, y, text, strlen(text)); +            EndPath(d->hDc); + +            // Now draw outline text +            oldPen = SelectObject(d->hDc, +                                  CreatePen(PS_SOLID, 1, +                                            mswGetColor(d->hasPalette, dc))); +            StrokePath(d->hDc); +            SelectObject(d->hDc, oldPen); +        } else { +            COLORREF old; + +            old = SetTextColor(d->hDc, mswGetColor(d->hasPalette, +                                                   dc)); +            TextOut(d->hDc, x, y, text, strlen(text)); +            SetTextColor(d->hDc, old);          } -        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); -        } -    } else { -        COLORREF old; -        prevFont = SelectObject(d->hDc, newFont); -        SetBkMode(d->hDc, TRANSPARENT); -        old = SetTextColor(d->hDc, mswGetColor(d->hasPalette, -                                               dc)); -        TextOut(d->hDc, x, y, text, strlen(text)); -        SetTextColor(d->hDc, old);          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); +            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; @@ -846,9 +908,9 @@ wFontSize_t wSelectedFontSize( void )  	return fontSize;  } -void wSetSelectedFontSize(int size) +void wSetSelectedFontSize(wFontSize_t size)  { -	fontSize = (wFontSize_t)size; +	fontSize = size;  }  /* @@ -870,10 +932,18 @@ void wDrawFilledRectangle(  		wDrawColor color,  		wDrawOpts opts )  { +	int mode;  	RECT rect;  	if (d == NULL)  		return; -	setDrawBrush( d->hDc, d, color, opts ); +	setDrawBrush( d, color, opts ); +	if (opts & wDrawOptTransparent) { +		mode = R2_NOTXORPEN; +	} +	else { +		mode = R2_COPYPEN; +	} +	SetROP2(d->hDc, mode);  	rect.left = XINCH2PIX(d,px);  	rect.right = XINCH2PIX(d,px+sx);  	rect.top = YINCH2PIX(d,py+sy); @@ -903,103 +973,230 @@ void wDrawFilledRectangle(  }  #ifdef DRAWFILLPOLYLOG -static FILE * logF; +    static FILE * logF;  #endif -static int wFillPointsMax = 0; -static POINT * wFillPoints; + +static dynArr_t wFillPoints_da; +static dynArr_t wFillType_da; + +#define POINTTYPE(N) DYNARR_N( BYTE, wFillType_da, (N) ) +#define POINTPOS(N) DYNARR_N( POINT, wFillPoints_da, (N) ) + +/** + * Add a point definition to the list. The clipping rectangle is recalculated to + * include the new point. + * + * \param d IN drawing context + * \param pk IN index of new point + * \param pp IN pointer to the point's coordinates + * \param type IN line type + * \param pr IN/OUT clipping rectangle + */  static void addPoint( -		int * pk, -		POINT * pp, -		RECT * pr ) +    wDraw_p d, +    int pk, +    coOrd * pp, +    BYTE type, RECT * pr)  { +    POINT p; +    p.x = XINCH2PIX(d, pp->x); +    p.y = YINCH2PIX(d, pp->y); +  #ifdef DRAWFILLPOLYLOG -fprintf( logF, "	q[%d] = {%d,%d}\n", *pk, pp->x, pp->y ); +    fprintf(logF, "	q[%d] = {%d,%d}\n", pk, p.x, p.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; + +    DYNARR_N(POINT, wFillPoints_da, pk) = p; +    DYNARR_N(BYTE, wFillType_da, pk) = type; + +    if (p.x < pr->left) { +        pr->left = p.x; +    } +    if (p.x > pr->right) { +        pr->right = p.x; +    } +    if (p.y < pr->top) { +        pr->top = p.y; +    } +    if (p.y > pr->bottom) { +        pr->bottom = p.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; +/** + * Draw a polyline consisting of straights with smoothed or rounded corners. + * Optionally the area can be filled. + * + * \param d	IN	drawing context + * \param node IN 2 dimensional array of coordinates + * \param type IN type of corener (vertex, smooth or round) + * \param cnt IN number of points + * \param color IN color + * \param dw IN line width + * \param lt IN line type + * \param opts IN drawing options + * \param fill IN area will be filled if true + * \param open IN do not close area + */ -	if (d == NULL) -		return; -	if (cnt*2 > wFillPointsMax) { -		wFillPoints = realloc( wFillPoints, cnt * 2 * sizeof *(POINT*)NULL ); -		if (wFillPoints == NULL) { -			fputs("can't realloc wFillPoints\n", stderr); -			abort(); +void wDrawPolygon( +    wDraw_p d, +    wPos_t node[][2], +    wPolyLine_e type[], +    wIndex_t cnt, +    wDrawColor color, +    wDrawWidth dw, +    wDrawLineType_e lt, +    wDrawOpts opts, +    int fill, +    int open) +{ +    RECT rect; +    int i, prevNode, nextNode; +    int pointCount = 0; +    coOrd endPoint0, endPoint1, controlPoint0, controlPoint1; +    coOrd point, startingPoint; +    BOOL rc; +    int closed = 0; + +    if (d == NULL) { +        return; +    } + +    // make sure the array for the points is large enough +    // worst case are rounded corners that require 4 points +    DYNARR_RESET(POINT,wFillPoints_da); +    DYNARR_SET(POINT,wFillPoints_da,(cnt + 1) * 4); +    DYNARR_RESET(BYTE,wFillType_da); +    DYNARR_SET(POINT,wFillType_da, (cnt + 1) * 4); + +    BeginPath(d->hDc); + +    if (fill) { +		int mode; +        setDrawBrush(d, color, opts); +		if (opts & wDrawOptTransparent) { +			mode = R2_NOTXORPEN;  		} -		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 ); +		else { +			mode = R2_COPYPEN;  		} -	} -	if ( p1Clipped && -		 ( wFillPoints[k-1].x > wFillPoints[k-1].y ) != ( wFillPoints[0].x > wFillPoints[0].y ) ) -		addPoint( &k, &zero, &rect ); +		SetROP2(d->hDc, mode); + +    } else { +        setDrawMode(d, dw, lt, color, opts); +    } + +    rect.left = rect.right = XINCH2PIX(d,node[cnt-1][0]-1); +    rect.top = rect.bottom = YINCH2PIX(d,node[cnt-1][1]+1); +  #ifdef DRAWFILLPOLYLOG -fflush( logF ); -fclose( logF ); +    logF = fopen("log.txt", "a"); +    fprintf(logF, "\np[%d] = {%d,%d}\n", cnt-1, node[0][0], node[0][1]);  #endif -	if ( k <= 2 ) -		return; -	Polygon( d->hDc, wFillPoints, k ); -	if (d->hWnd) { -		rect.top--; -		rect.left--; -		rect.bottom++; -		rect.right++; -		myInvalidateRect( d, &rect ); -	} + +    for (i=0; i<cnt; i++) { +        wPolyLine_e type1; +        point.x = node[i][0]; +        point.y = node[i][1]; +		if (type != NULL) +			type1 = type[i]; +		else +			type1 = wPolyLineStraight; + +        if (type1 == wPolyLineRound || type1 == wPolyLineSmooth) { +            prevNode = (i == 0) ? cnt - 1 : i - 1; +            nextNode = (i == cnt - 1) ? 0 : i + 1; + +            // calculate distance to neighboring nodes +            int prevXDistance = node[i][0] - node[prevNode][0]; +            int prevYDistance = node[i][1] - node[prevNode][1]; +            int nextXDistance = node[nextNode][0]-node[i][0]; +            int nextYDistance = node[nextNode][1]-node[i][1]; + +            // distance from node to endpoints of curve is half the line length +            endPoint0.x = (prevXDistance/2)+node[prevNode][0]; +            endPoint0.y = (prevYDistance/2)+node[prevNode][1]; +            endPoint1.x = (nextXDistance/2)+node[i][0]; +            endPoint1.y = (nextYDistance/2)+node[i][1]; + +            if (type1 == wPolyLineRound) { +                double distNext = (nextXDistance*nextXDistance + nextYDistance * nextYDistance); +                double distPrev = (prevXDistance*prevXDistance + prevYDistance * prevYDistance); +                // but should be half of the shortest line length (equidistant from node) for round +                if ((distPrev > 0) && (distNext > 0)) { +                    double ratio = sqrt(distPrev / distNext); +                    if (distPrev < distNext) { +                        endPoint1.x = ((nextXDistance*ratio) / 2) + node[i][0]; +                        endPoint1.y = ((nextYDistance*ratio) / 2) + node[i][1]; +                    } else { +                        endPoint0.x = node[i][0] - (prevXDistance / (2 * ratio)); +                        endPoint0.y = node[i][1] - (prevYDistance / (2 * ratio)); +                    } +                } +                // experience says that the best look is achieved if the +                // control points are in the middle between end point and node +                controlPoint0.x = (node[i][0] - endPoint0.x) / 2 + endPoint0.x; +                controlPoint0.y = (node[i][1] - endPoint0.y) / 2 + endPoint0.y; + +                controlPoint1.x = (endPoint1.x - node[i][0]) / 2 + node[i][0]; +                controlPoint1.y = (endPoint1.y - node[i][1]) / 2 + node[i][1]; +            } else { +                controlPoint0 = point; +                controlPoint1 = point; +            } +        } + +        if (i==0) { +            if (type1 == wPolyLineStraight || open) { +                // for straight lines or open shapes use the starting point as passed +                addPoint(d, pointCount++, &point, PT_MOVETO, &rect); +                startingPoint = point; +            } else { +                // for Bezier begin with the calculated starting point +                addPoint(d, pointCount++, &endPoint0, PT_MOVETO, &rect); +                addPoint(d, pointCount++, &controlPoint0, PT_BEZIERTO, &rect); +                addPoint(d, pointCount++, &controlPoint1, PT_BEZIERTO, &rect); +                addPoint(d, pointCount++, &endPoint1, PT_BEZIERTO, &rect); +                startingPoint = endPoint0; +            } +        } else { +            if (type1 == wPolyLineStraight || (open && (i==cnt-1))) { +                addPoint(d, pointCount++, &point, PT_LINETO, &rect); +            } else { +                if (i==cnt-1 && !open) { +                    closed = TRUE; +                } +                addPoint(d, pointCount++, &endPoint0, PT_LINETO, &rect); +                addPoint(d, pointCount++, &controlPoint0, PT_BEZIERTO, &rect); +                addPoint(d, pointCount++, &controlPoint1, PT_BEZIERTO, &rect); +                addPoint(d, pointCount++, &endPoint1, +                         PT_BEZIERTO | (closed ? PT_CLOSEFIGURE : 0), &rect); +            } +        } +    } + +    if (!open && !closed) { +        addPoint(d, pointCount++, &startingPoint, PT_LINETO, &rect); +    } +    rc = PolyDraw(d->hDc, wFillPoints_da.ptr, wFillType_da.ptr, pointCount); + +    EndPath(d->hDc); + +    if (fill && !open) { +        FillPath(d->hDc); +    } else { +        StrokePath(d->hDc); +    } + +    if (d->hWnd) { +        rect.top--; +        rect.left--; +        rect.bottom++; +        rect.right++; +        myInvalidateRect(d, &rect); +    }  }  #define MAX_FILLCIRCLE_POINTS	(30) @@ -1022,7 +1219,7 @@ void wDrawFilledCircle(  	p1.x = XINCH2PIX(d,x+r);  	p1.y = YINCH2PIX(d,y-r)+1; -	setDrawBrush( d->hDc, d, color, opts );						   +	setDrawBrush( d, color, opts );						    	if ( noNegDrawArgs > 0 && ( p0.x < 0 || p0.y < 0 ) ) {  		if ( r > MAX_FILLCIRCLE_POINTS )  			cnt = MAX_FILLCIRCLE_POINTS; @@ -1035,7 +1232,8 @@ void wDrawFilledCircle(  			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 ); +		//wDrawFilledPolygon( d, circlePts, NULL, cnt, color, opts ); +		wDrawPolygon(d, circlePts, NULL, cnt, color, 1, wDrawLineSolid,opts, TRUE, FALSE );  	} else {  		Ellipse( d->hDc, p0.x, p0.y, p1.x, p1.y );  		if (d->hWnd) { @@ -1084,21 +1282,30 @@ void wDrawRestoreImage(  } -void wDrawClear( wDraw_p d ) +void wDrawClearTemp( wDraw_p d )  {  	RECT rect; -	SetROP2( d->hDc, R2_WHITE ); -	Rectangle( d->hDc, 0, 0, d->w, d->h ); +	SelectObject( d->hDc, d->hBmTemp ); +	BitBlt(d->hDc, 0, 0, d->w, d->h, d->hDc, 0, 0, WHITENESS);  	if (d->hWnd) { -	rect.top = 0; -	rect.bottom = d->h; -	rect.left = 0; -	rect.right = d->w; -	InvalidateRect( d->hWnd, &rect, FALSE ); +		rect.top = 0; +		rect.bottom = d->h; +		rect.left = 0; +		rect.right = d->w; +		InvalidateRect( d->hWnd, &rect, FALSE );  	}  } +void wDrawClear( wDraw_p d ) +{ +	SelectObject( d->hDc, d->hBmMain ); +	// BitBlt is faster than Rectangle +	BitBlt(d->hDc, 0, 0, d->w, d->h, d->hDc, 0, 0, WHITENESS); +	wDrawClearTemp(d); +} + +  void wDrawSetSize(  		wDraw_p d,  		wPos_t width, @@ -1196,7 +1403,7 @@ void wDrawBitMap(  		wDrawColor dc,  		wDrawOpts dopt )  { -	HDC bmDc, hDc; +	HDC bmDc;  	HBITMAP oldBm;  	DWORD mode;  	int x0, y0; @@ -1208,9 +1415,7 @@ void wDrawBitMap(  	if ( noNegDrawArgs > 0 && ( x0 < 0 || y0 < 0 ) )  		return;  #endif -	if (dopt & wDrawOptTemp) { -		mode = tmpOp; -	} else if (dc == wDrawColorWhite) { +	if (dc == wDrawColorWhite) {  		mode = clrOp;  		dc = wDrawColorBlack;  	} else { @@ -1224,22 +1429,9 @@ void wDrawBitMap(  				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 ); +	setDrawMode( 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 ); @@ -1260,7 +1452,7 @@ wDrawBitMap_p wDrawBitMapCreate(  		int h,  		int x,  		int y, -		const char * bits ) +		const unsigned char * bits )  {  	wDrawBitMap_p bm;  	int bmSize = ((w+7)/8) * h; @@ -1322,12 +1514,14 @@ long FAR PASCAL XEXPORT mswDrawPush(  		hDc = GetDC(hWnd);  		if ( b->option & BD_DIRECT ) {  			b->hDc = hDc; -			b->hBm = 0; +			b->hBmMain = 0; +			b->hBmTemp = 0;  			b->hBmOld = 0;  		} else {  			b->hDc = CreateCompatibleDC( hDc );  -			b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); -			b->hBmOld = SelectObject( b->hDc, b->hBm ); +			b->hBmMain = CreateCompatibleBitmap( hDc, b->w, b->h ); +			b->hBmTemp = CreateCompatibleBitmap( hDc, b->w, b->h ); +			b->hBmOld = SelectObject( b->hDc, b->hBmMain );  		}  		if (mswPalette) {  			SelectPalette( b->hDc, mswPalette, 0 ); @@ -1355,8 +1549,12 @@ long FAR PASCAL XEXPORT mswDrawPush(  			if ( b->option & BD_DIRECT ) {  			} else {  			hDc = GetDC( b->hWnd ); -			b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); -			DeleteObject(SelectObject( b->hDc, b->hBm )); +//-			DeleteObject( b->hBmOld ); +			DeleteObject( b->hBmMain ); +			DeleteObject( b->hBmTemp ); +			b->hBmMain = CreateCompatibleBitmap( hDc, b->w, b->h ); +			b->hBmTemp = CreateCompatibleBitmap( hDc, b->w, b->h ); +//-			b->hBmOld = SelectObject( b->hDc, b->hBmMain );  			ReleaseDC( b->hWnd, hDc );  			SetROP2( b->hDc, R2_WHITE );  			Rectangle( b->hDc, 0, 0, b->w, b->h ); @@ -1383,6 +1581,7 @@ long FAR PASCAL XEXPORT mswDrawPush(  	case WM_LBUTTONUP:  	case WM_RBUTTONDOWN:  	case WM_RBUTTONUP: +	case WM_LBUTTONDBLCLK:  		if (message == WM_LBUTTONDOWN)  			action = wActionLDown;  		else if (message == WM_RBUTTONDOWN) @@ -1391,6 +1590,8 @@ long FAR PASCAL XEXPORT mswDrawPush(  			action = wActionLUp;  		else if (message == WM_RBUTTONUP)  			action = wActionRUp; +		else if (message == WM_LBUTTONDBLCLK) +			action = wActionLDownDouble;  		else {  			if ( (wParam & MK_LBUTTON) != 0)  				action = wActionLDrag; @@ -1414,6 +1615,8 @@ long FAR PASCAL XEXPORT mswDrawPush(  		iy = HIWORD( lParam );  		x = XPIX2INCH( b, ix );  		y = YPIX2INCH( b, iy ); +		b->lastX = x; +		b->lastY = y;  		if (b->action)  			b->action( b, b->data, action, x, y );  		if (b->hWnd) @@ -1435,7 +1638,7 @@ long FAR PASCAL XEXPORT mswDrawPush(  		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_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; @@ -1450,9 +1653,9 @@ long FAR PASCAL XEXPORT mswDrawPush(  		}  		if (b && b->action) {  			if (extChar != wAccelKey_None) -				b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), 0, 0 ); +				b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), b->lastX, b->lastY );  			else -				b->action( b, b->data, wActionText + ( wParam << 8 ), 0, 0 ); +				b->action( b, b->data, wActionText + ( wParam << 8 ), b->lastX, b->lastY );  		}  		return 0; @@ -1468,11 +1671,22 @@ long FAR PASCAL XEXPORT mswDrawPush(  						b->paletteClock = winPaletteClock;  					}  				} +				HBITMAP hBmOld = SelectObject( b->hDc, b->hBmMain ); + +			if (bDrawMainBM) { +				BitBlt(hDc, rect.left, rect.top, +					rect.right - rect.left, rect.bottom - rect.top, +					b->hDc, rect.left, rect.top, +					SRCCOPY); +			} +				SelectObject( b->hDc, b->bCopiedMain?b->hBmTemp:b->hBmMain );  				BitBlt( hDc, rect.left, rect.top,  						rect.right-rect.left, rect.bottom-rect.top,  						b->hDc, rect.left, rect.top, -						SRCCOPY ); +						bDrawMainBM?SRCAND:SRCCOPY); +				SelectObject( b->hDc, hBmOld );  				EndPaint( hWnd, &ps ); +				b->bCopiedMain = FALSE;  			}  		}  		break; @@ -1499,18 +1713,44 @@ long FAR PASCAL XEXPORT mswDrawPush(  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; +		if (GET_KEYSTATE_WPARAM(wParam) & (MK_SHIFT|MK_MBUTTON) ) { +			if (GET_KEYSTATE_WPARAM(wParam) & MK_CONTROL ) { +				if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) { +					action = wActionScrollLeft; +				} else { +					action = wActionScrollRight; +				} +			} else { +				if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) { +					action = wActionScrollUp; +				} else { +					action = wActionScrollDown; +				} +			}  		} else { -			action = wActionWheelDown; +			if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) { +				action = wActionWheelUp; +			} else { +				action = wActionWheelDown; +			} +		} +		if (b->action) +			b->action( b, b->data, action, b->lastX, b->lastY ); +		return 0; +	case WM_MOUSEHWHEEL: +		if ( GET_KEYSTATE_WPARAM(wParam) & (MK_SHIFT|MK_MBUTTON)) { +			if ( GET_WHEEL_DELTA_WPARAM(wParam) > 0 ) { +				action = wActionScrollRight; +			} else { +				action = wActionScrollLeft; +			}  		}  		if (b->action) -			b->action( b, b->data, action, 0, 0 ); +			b->action( b, b->data, action, b->lastX, b->lastY );  		return 0;  	} @@ -1521,10 +1761,12 @@ static LRESULT drawMsgProc( wDraw_p b, HWND hWnd, UINT message, WPARAM wParam, L  static void drawDoneProc( wControl_p b )  {  	wDraw_p d = (wDraw_p)b; -	if (d->hBm) { +	if (d->hBmMain) {  		SelectObject( d->hDc, d->hBmOld ); -		DeleteObject( d->hBm ); -		d->hBm = (HBITMAP)0; +		DeleteObject( d->hBmMain ); +		d->hBmMain = (HBITMAP)0; +		DeleteObject( d->hBmTemp ); +		d->hBmTemp = (HBITMAP)0;  	}  	if (d->hPen) {  		SelectObject( d->hDc, GetStockObject( BLACK_PEN ) ); @@ -1580,10 +1822,17 @@ void mswRepaintAll( void )  	for ( b=drawList; b; b=b->drawNext ) {  		if (GetUpdateRect( b->hWnd, &rect, FALSE )) {  			hDc = BeginPaint( b->hWnd, &ps ); +			HBITMAP hBmOld = SelectObject( b->hDc, b->hBmMain );  			BitBlt( hDc, rect.left, rect.top,  						rect.right-rect.left, rect.bottom-rect.top,  						b->hDc, rect.left, rect.top,  						SRCCOPY ); +			SelectObject( b->hDc, b->hBmTemp ); +			BitBlt( hDc, rect.left, rect.top, +						rect.right-rect.left, rect.bottom-rect.top, +						b->hDc, rect.left, rect.top, +						SRCAND ); +			SelectObject( b->hDc, hBmOld );  			EndPaint( b->hWnd, &ps );  		}  	} @@ -1648,6 +1897,7 @@ wDraw_p wDrawCreate(  		SelectPalette( hDc, mswPalette, 0 );  		ReleaseDC( d->hWnd, hDc );  	} +	d->bCopiedMain = FALSE;  	return d;  } @@ -1681,14 +1931,19 @@ wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes )  		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 ); +	d->hBmMain = CreateCompatibleBitmap( hDc, d->w, d->h ); +	if ( d->hBmMain == (HBITMAP)0 ) { +		wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM Main fails", "Ok", NULL ); +		return FALSE; +	} +	d->hBmTemp = CreateCompatibleBitmap( hDc, d->w, d->h ); +	if ( d->hBmTemp == (HBITMAP)0 ) { +		wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM Temp fails", "Ok", NULL );  		return FALSE;  	}  	d->hasPalette = (GetDeviceCaps(hDc,RASTERCAPS ) & RC_PALETTE) != 0;  	ReleaseDC( mswHWnd, hDc ); -	d->hBmOld = SelectObject( d->hDc, d->hBm ); +	d->hBmOld = SelectObject( d->hDc, d->hBmMain );  	if (mswPalette) {  		SelectPalette( d->hDc, mswPalette, 0 );  		RealizePalette( d->hDc ); @@ -1697,8 +1952,9 @@ wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes )  	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 ); +	wDrawClear(d); +//-	SetROP2( d->hDc, R2_WHITE ); +//-	Rectangle( d->hDc, 0, 0, d->w, d->h );  	return d;  } @@ -1709,10 +1965,12 @@ wBool_t wBitMapDelete( wDraw_p d )  		DeleteObject( d->hPen );  		d->hPen = (HPEN)0;  	} -	if (d->hBm) { +	if (d->hBmMain) {  		SelectObject( d->hDc, d->hBmOld ); -		DeleteObject( d->hBm ); -		d->hBm = (HBITMAP)0; +		DeleteObject( d->hBmMain ); +		d->hBmMain = (HBITMAP)0; +		DeleteObject( d->hBmTemp ); +		d->hBmTemp = (HBITMAP)0;  	}  	if (d->hDc) {  		DeleteDC( d->hDc ); @@ -1722,74 +1980,75 @@ wBool_t wBitMapDelete( wDraw_p d )  	return TRUE;  } -wBool_t wBitMapWriteFile( wDraw_p d, const char * fileName ) +/** + * write bitmap file. The bitmap in d must contain a valid HBITMAP + * + * \param  d	    A wDraw_p to process. + * \param  fileName Filename of the file. + * + * \returns A wBool_t. TRUE on success + */ + +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; +    FIBITMAP *dib = NULL; +    FIBITMAP *dib2 = NULL; +    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; +    BOOL bSuccess = FALSE; + +    if (d->hBmMain) { + +        BITMAP bm; +        GetObject(d->hBmMain, sizeof(BITMAP), (LPSTR)&bm); +        dib = FreeImage_Allocate(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0, 0, 0); +        // The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why) +        // So we save these infos below. This is needed for palettized images only. +        int nColors = FreeImage_GetColorsUsed(dib); +        HDC dc = GetDC(NULL); +        GetDIBits(dc, +                  d->hBmMain, +                  0, +                  FreeImage_GetHeight(dib), +                  FreeImage_GetBits(dib), +                  FreeImage_GetInfo(dib), +                  DIB_RGB_COLORS); +        ReleaseDC(NULL, dc); + +        // restore BITMAPINFO members +        FreeImage_GetInfoHeader(dib)->biClrUsed = nColors; +        FreeImage_GetInfoHeader(dib)->biClrImportant = nColors; +        // we will get a 32 bit bitmap on Windows systems with invalid alpha +        // so it needs to be converted to 24 bits. +        // (see: https://sourceforge.net/p/freeimage/discussion/36110/thread/0699ce8e/ ) +        dib2 = FreeImage_ConvertTo24Bits(dib); +        FreeImage_Unload(dib); +    } + +    // Try to guess the file format from the file extension +    fif = FreeImage_GetFIFFromFilename(fileName); +    if (fif != FIF_UNKNOWN) { +        // Check that the dib can be saved in this format +        BOOL bCanSave; + +        FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib2); +        if (image_type == FIT_BITMAP) { +            // standard bitmap type +            WORD bpp = FreeImage_GetBPP(dib2); +            bCanSave = (FreeImage_FIFSupportsWriting(fif) && +                        FreeImage_FIFSupportsExportBPP(fif, bpp)); +        } else { +            // special bitmap type +            bCanSave = FreeImage_FIFSupportsExportType(fif, image_type); +        } + +        if (bCanSave) { +            bSuccess = FreeImage_Save(fif, dib2, fileName, PNG_DEFAULT); +            return bSuccess; +        } +    } +    FreeImage_Unload(dib2); + +    return bSuccess;  } diff --git a/app/wlib/mswlib/mswedit.c b/app/wlib/mswlib/mswedit.c index fbae89f..dc70ac3 100644 --- a/app/wlib/mswlib/mswedit.c +++ b/app/wlib/mswlib/mswedit.c @@ -1,3 +1,25 @@ +/** \file mswedit.c + * Text entry widgets + */ +  +/*  XTrackCAD - Model Railroad CAD + *  Copyright (C) 2005 Dave Bullis + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +   #include <windows.h>  #include <string.h>  #include <malloc.h> @@ -15,6 +37,7 @@ struct wString_t {  		wStringCallBack_p action;  		}; +#ifdef LATER  struct wInteger_t {  		WOBJ_COMMON  		long low, high; @@ -30,6 +53,7 @@ struct wFloat_t {  		double oldValue;  		wFloatCallBack_p action;  		}; +#endif // LATER  static XWNDPROC oldEditProc = NULL; @@ -47,53 +71,35 @@ long FAR PASCAL _export pushEdit(  		UINT wParam,  		LONG lParam )  { -	/* Catch <Return> and cause focus to leave control */ +  #ifdef WIN32  	long inx = GetWindowLong( hWnd, GWL_ID );  #else  	short inx = GetWindowWord( hWnd, GWW_ID );  #endif -	wControl_p b = mswMapIndex( inx ); +	wControl_p b = mswMapIndex(inx); -	switch (message) { +	switch (message) +	{  	case WM_CHAR: -		if ( b != NULL) { -			switch( wParam ) { -			case 0x0D: -			case 0x1B: -			case 0x09: -				SetFocus( ((wControl_p)(b->parent))->hWnd );  -				SendMessage( ((wControl_p)(b->parent))->hWnd, WM_CHAR, -						wParam, lParam ); -				/*SendMessage( ((wControl_p)(b->parent))->hWnd, WM_COMMAND, -						inx, MAKELONG( hWnd, EN_KILLFOCUS ) );*/ -				return 0L; -			} -		} -		break; - -	case WM_KEYUP: -		if ( b != NULL) -			switch (b->type) { -			case B_STRING: -				if (((wString_p)b)->action) -					mswSetTrigger( (wControl_p)b, triggerString ); -				break; -#ifdef LATER -			case B_INTEGER: -				if (((wInteger_p)b)->action) -					mswSetTrigger( (wControl_p)b, triggerInteger ); -				break; -			case B_FLOAT: -				if (((wFloat_p)b)->action) -					mswSetTrigger( (wControl_p)b, triggerFloat ); -				break; -#endif -			} -		break; +	    if (b != NULL) { +	        switch (wParam) { +	        case VK_RETURN: +	            triggerString(b); +	            return (0L); +	            break; +	        case 0x1B: +	        case 0x09: +	            SetFocus(((wControl_p)(b->parent))->hWnd); +	            SendMessage(((wControl_p)(b->parent))->hWnd, WM_CHAR, +	                        wParam, lParam); +	            return 0L; +	        } +	    } +	    break;  	} -	return CallWindowProc( oldEditProc, hWnd, message, wParam, lParam ); +	return CallWindowProc(oldEditProc, hWnd, message, wParam, lParam);  }  /* @@ -112,7 +118,7 @@ void wStringSetValue(  	WORD len = (WORD)strlen( arg );  	SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)arg );  #ifdef WIN32 -	SendMessage( b->hWnd, EM_SETSEL, len, len ); +	SendMessage( b->hWnd, EM_SETSEL, 0, -1 );  	SendMessage( b->hWnd, EM_SCROLLCARET, 0, 0L );  #else  	SendMessage( b->hWnd, EM_SETSEL, 0, MAKELPARAM(len,len) ); @@ -140,60 +146,92 @@ const char * wStringGetValue(  	return buff;  } +/** + * Get the string from a entry field. The returned pointer has to be free() after processing is complete. + *  + * \param bs IN string entry field + *  + * \return    pointer to entered string or NULL if entry field is empty. + */ -static void triggerString( -		wControl_p b ) +static char *getString(wString_p bs)  { -	wString_p bs = (wString_p)b; -	int cnt; +    char *tmpBuffer = NULL; +    UINT chars = SendMessage(bs->hWnd, EM_LINELENGTH, (WPARAM)0, 0L); -	if (bs->action) { -		*(WPARAM*)&mswTmpBuff[0] = 78; -		cnt = (int)SendMessage( bs->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); -		mswTmpBuff[cnt] = '\0'; -		if (bs->valueP) -			strcpy( bs->valueP, mswTmpBuff ); -		bs->action( mswTmpBuff, bs->data ); -		mswSetTrigger( NULL, NULL ); -	} +    if (chars) { +        tmpBuffer = malloc(chars > sizeof(WORD)? chars + 1 : sizeof(WORD) + 1); +        *(WORD *)tmpBuffer = chars; +        SendMessage(bs->hWnd, (UINT)EM_GETLINE, 0, (LPARAM)tmpBuffer); +        tmpBuffer[chars] = '\0'; +    } + +    return (tmpBuffer);  } +/** + * Retrieve and process string entry. If a string has been entered, the callback for + * the specific entry field is called. + * + * \param b IN string entry field + */ -LRESULT stringProc( -		wControl_p b, -		HWND hWnd, -		UINT message, -		WPARAM wParam, -		LPARAM lParam ) +static void triggerString( +    wControl_p b)  { -	wString_p bs = (wString_p)b; -	int cnt; -	int modified; - -	switch( message ) { - -	case WM_COMMAND: -		switch (WCMD_PARAM_NOTF) { -		case EN_KILLFOCUS: -			modified = (int)SendMessage( bs->hWnd, (UINT)EM_GETMODIFY, 0, 0L ); -			if (!modified) -				break; -			*(WPARAM*)&mswTmpBuff[0] = 78; -			cnt = (int)SendMessage( bs->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); -			mswTmpBuff[cnt] = '\0'; -			if (bs->valueP) -				strncpy( bs->valueP, mswTmpBuff, bs->valueL ); -			if (bs->action) { -				bs->action( mswTmpBuff, bs->data ); -				mswSetTrigger( NULL, NULL ); -			} -			break; -			SendMessage( bs->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L ); -		} -		break; +    wString_p bs = (wString_p)b; + +    char *enteredString = getString(bs); +    if (enteredString) +    { +        if (bs->valueP) { +            strcpy(bs->valueP, enteredString); +        } +		if (bs->action) { +            bs->action(enteredString, bs->data); +        } +		free(enteredString);  	} +} -	return DefWindowProc( hWnd, message, wParam, lParam ); + +LRESULT stringProc( +    wControl_p b, +    HWND hWnd, +    UINT message, +    WPARAM wParam, +    LPARAM lParam) +{ +    wString_p bs = (wString_p)b; +    int modified; + +    switch (message) { + +    case WM_COMMAND: +        switch (WCMD_PARAM_NOTF) { +        case EN_KILLFOCUS: +            modified = (int)SendMessage(bs->hWnd, (UINT)EM_GETMODIFY, 0, 0L); +            if (!modified) { +                break; +            } + +            char *enteredString = getString(bs); +            if (enteredString) { +                if (bs->valueP) { +                    strcpy(bs->valueP, enteredString); +                } +                if (bs->action) { +                    bs->action(enteredString, bs->data); +                    mswSetTrigger(NULL, NULL); +                } +                free(enteredString); +            } +            SendMessage(bs->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L); +        } +        break; +    } + +    return DefWindowProc(hWnd, message, wParam, lParam);  } @@ -249,10 +287,6 @@ wString_p wStringCreate(  		return b;  	} -#ifdef CONTROL3D -	Ctl3dSubclassCtl( b->hWnd); -#endif -  	newEditProc = MakeProcInstance( (XWNDPROC)pushEdit, mswHInst );  	oldEditProc = (XWNDPROC)GetWindowLong(b->hWnd, GWL_WNDPROC );  	SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newEditProc ); diff --git a/app/wlib/mswlib/mswint.h b/app/wlib/mswlib/mswint.h index 2311415..e560053 100644 --- a/app/wlib/mswlib/mswint.h +++ b/app/wlib/mswlib/mswint.h @@ -1,6 +1,7 @@  #include "wlib.h"  #include "mswlib.h" -#include "dynarr.h" +//#include "dynarr.h" +#include "common.h"  #ifndef WIN32  /*#define CONTROL3D*/  #endif @@ -38,7 +39,9 @@  #define WSCROLL_PARAM_HWND	HIWORD(lParam)  #endif -#define CAST_AWAY_CONST (char *) +#ifndef CAST_AWAY_CONST +	#define CAST_AWAY_CONST (char *) +#endif  #define BOOL_T wBool_t  #define POS_T wPos_t @@ -122,16 +125,24 @@ struct wDraw_t {  		double DPI;  		wDrawRedrawCallBack_p drawRepaint;  		wDrawActionCallBack_p action; -		HBITMAP hBm; +		HBITMAP hBmMain; +		HBITMAP hBmTemp; +		HBITMAP hBmOld;  		HPEN hPen;  		HBRUSH hBrush;  		wDraw_p drawNext; -		HBITMAP hBmOld;  		wBool_t hasPalette;  		int paletteClock;  		HBITMAP hBmBackup;  		HDC hDcBackup;  		HBITMAP hBmBackupOld; +		void *background; +		wBool_t bTempMode; +		wBool_t bCopiedMain; + +		wPos_t lastX; +		wPos_t lastY; +  		};  extern HINSTANCE mswHInst; @@ -147,6 +158,7 @@ extern wDrawColor wDrawColorWhite;  extern wDrawColor wDrawColorBlack;  extern long mswThickFont;  extern double mswScale; +extern double scaleIcon;  DWORD mswGetBaseStyle( wWin_p );  char * mswStrdup( const char * ); @@ -190,4 +202,5 @@ void deleteBitmaps( void );  void mswDrawIcon( HDC, int, int, wIcon_p, int, COLORREF, COLORREF );  /* gwin32.c*/ -char *g_win32_getlocale (void);
\ No newline at end of file +char *g_win32_getlocale (void); + diff --git a/app/wlib/mswlib/mswlist.c b/app/wlib/mswlib/mswlist.c index 2453a5e..95ecec3 100644 --- a/app/wlib/mswlib/mswlist.c +++ b/app/wlib/mswlib/mswlist.c @@ -243,7 +243,7 @@ wBool_t wListSetValues(  		void * itemData )  {  	listData * ldp;		 -	WORD curSel; +	WORD curSel = -1;  	ldp = (listData*)malloc( sizeof *ldp );  	ldp->itemContext = itemData;  	ldp->bm = bm; diff --git a/app/wlib/mswlib/mswmenu.c b/app/wlib/mswlib/mswmenu.c index 815752a..d56e24d 100644 --- a/app/wlib/mswlib/mswmenu.c +++ b/app/wlib/mswlib/mswmenu.c @@ -31,6 +31,7 @@  #include <math.h>  #include <ctype.h>  #include <assert.h> +#include "misc.h"  #include "mswint.h"  #include "i18n.h" @@ -579,7 +580,7 @@ wMenuPush_p wMenuPushCreate(  {  	wMenuPush_p mi;  	int rc; -	char label[80]; +	char *label = malloc(strlen(labelStr) + 30 );	/**< The label and sufficient space for the keyboard shortcut */  	char *cp;  	char ac;  	UINT vk; @@ -591,9 +592,9 @@ wMenuPush_p wMenuPushCreate(  	mi->mparent = m;  	mi->acclKey = acclKey;  	mi->enabled = TRUE; -	strcpy( label, mi->labelStr ); +	strcpy(label, labelStr);  	modifier = 0; -	if ( acclKey != 0 ) { +	if ( acclKey != 0 && strlen(label ) < 60 ) {  		DYNARR_APPEND( acclTable_t, acclTable_da, 10 );  		cp = label + strlen( label );  		*cp++ = '\t'; @@ -625,6 +626,7 @@ wMenuPush_p wMenuPushCreate(  		acclTable(acclTable_da.cnt-1).mp = mi;  	}  	rc = AppendMenu( m->menu, MF_STRING, mi->index, label ); +	free(label);  	return mi;  } diff --git a/app/wlib/mswlib/mswmisc.c b/app/wlib/mswlib/mswmisc.c index e045cc8..6b5f1c9 100644 --- a/app/wlib/mswlib/mswmisc.c +++ b/app/wlib/mswlib/mswmisc.c @@ -22,6 +22,7 @@  #define _WIN32_WINNT 0x0500  #include <windows.h> +#include <shellapi.h>  #include <string.h>  #include <malloc.h>  #include <stdlib.h> @@ -30,8 +31,10 @@  #include <stdio.h>  #include <assert.h>  #include <htmlhelp.h> +#include "misc.h"  #include "mswint.h"  #include "i18n.h" +#include "FreeImage.h"  #if _MSC_VER > 1300  #define stricmp _stricmp @@ -47,6 +50,8 @@ char * mswStrdup(const char *);  #define ALARM_TIMER		(902)  #define BALLOONHELP_TIMER		(903)  #define TRIGGER_TIMER	(904) +#define CONTROLHILITEWIDTH (2) +#define CONTROLHILITECOLOR (RGB(0x3a,0x5f,0xcd))  #define WANT_LITTLE_LABEL_FONT @@ -78,6 +83,8 @@ HFONT mswLabelFont;  long mswThickFont = 1;  double mswScale = 1.0; +double scaleIcon = 1.0;				   /**< Scaling factor for toolbar icons */ +  callBacks_t *mswCallBacks[CALLBACK_CNT];  void closeBalloonHelp(void); @@ -87,7 +94,12 @@ static wControl_p getControlFromCursor(HWND, wWin_p *);   */  struct wWin_t { -    WOBJ_COMMON +	WOBJ_COMMON +	int validGeometry; +	int min_width; +	int max_width; +	int min_height; +	int max_height;      wPos_t lastX, lastY;      wPos_t padX, padY;      wControl_p first, last; @@ -174,7 +186,21 @@ static int dumpControls;  extern char *userLocale; - +// list of supported fileformats for image files +char * filterImageFiles[] = { N_("All image files"), +							"*.gif;*.jpg;*.jpeg;*.png;*.tif;*.tiff", +							N_("GIF files (*.gif)"), +							"*.gif", +							N_("JPEG files (*.jpeg,*.jpg)"), +							"*.jpg;*.jpeg", +							N_("PNG files (*.png)"), +							"*.png", +							N_("TIFF files (*.tiff, *.tif)"), +							"*.tif;*.tiff", +							N_("All files (*)"), +							"*", +							}; +  /*   *****************************************************************************   * @@ -610,6 +636,35 @@ static void getSavedSizeAndPos(  }  /** + * Set min and max dimensions for a window.  + * + * \param min_width IN minimum width of window + * \param max_width IN maximum width of window + * \param min_height IN minimum height of window + * \param max_height IN maximum height of window + * \param base_width IN unused on Windows + * \param base_height IN unused on Windows + * \param aspect_ration IN unused on Windows + */ +void wSetGeometry(wWin_p win, +	int min_width, +	int max_width, +	int min_height, +	int max_height, +	int base_width, +	int base_height, +	double aspect_ratio) +{ +	win->validGeometry = TRUE;	//remember that geometry was set +	win->min_width = min_width; +	win->max_width = max_width; +	win->min_height = min_height; +	win->max_height = max_height; + +	return; +} + +/**   * Create a window. Retrieves the saved size and position and restores the created window accordingly.   *   * \param hWnd IN parent window @@ -812,6 +867,10 @@ wWin_p wWinMainCreate(  	wPrefGetInteger("draw", "maximized", &maximize, 0L);  	option |= (maximize ? F_MAXIMIZE : 0); +	wPrefGetFloat(PREFSECTION, LARGEICON, &scaleIcon, 1.0); +	if (scaleIcon < 1.0) scaleIcon = 1.0; +	if (scaleIcon > 2.0) scaleIcon = 2.0; +      showCmd = SW_SHOW;      w = winCommonCreate(NULL, W_MAIN, option|F_RESIZE, "MswMainWindow",                          WS_OVERLAPPEDWINDOW, labelStr, winProc, x, y, data, @@ -819,13 +878,10 @@ wWin_p wWinMainCreate(      mswHWnd = w->hWnd;      if (!mswThickFont) { -        DWORD dw;          SendMessage(w->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L);          hDc = GetDC(w->hWnd);          GetTextMetrics(hDc, &tm);          mswEditHeight = tm.tmHeight+2; -        dw = GetTextExtent(hDc, "AXqypj", 6); -        mswEditHeight = HIWORD(dw)+2;          ReleaseDC(w->hWnd, hDc);      } @@ -1380,12 +1436,11 @@ void wWinClear(  {  } -void wSetCursor( +void wSetCursor(wDraw_p win,      wCursor_t cursor)  {      switch (cursor) {      case wCursorNormal: -    case wCursorQuestion:      default:          SetCursor(LoadCursor(NULL, IDC_ARROW));          break; @@ -1401,6 +1456,42 @@ void wSetCursor(      case wCursorIBeam:          SetCursor(LoadCursor(NULL, IDC_IBEAM));          break; + +    case wCursorQuestion: +    	SetCursor(LoadCursor(NULL, IDC_HELP)); +    	break; + +    case wCursorHand: +       	SetCursor(LoadCursor(NULL, IDC_HAND)); +       	break; + +    case wCursorNo: +       	SetCursor(LoadCursor(NULL, IDC_NO)); +       	break; + +    case wCursorSizeAll: +       	SetCursor(LoadCursor(NULL, IDC_SIZEALL)); +       	break; + +    case wCursorSizeNESW: +       	SetCursor(LoadCursor(NULL, IDC_SIZENESW)); +       	break; + +    case wCursorSizeNWSE: +       	SetCursor(LoadCursor(NULL, IDC_SIZENWSE)); +       	break; + +    case wCursorSizeNS: +       	SetCursor(LoadCursor(NULL, IDC_SIZENS)); +       	break; + +    case wCursorSizeWE: +       	SetCursor(LoadCursor(NULL, IDC_SIZEWE)); +       	break; + +    case wCursorAppStart: +    	SetCursor(LoadCursor(NULL, IDC_APPSTARTING)); +        break;      }      curCursor = cursor; @@ -1663,7 +1754,7 @@ void wControlSetLabel(      wControl_p b,      const char * labelStr)  { -    if (b->type == B_RADIO || b->type == B_TOGGLE) { +    if (b->type == B_RADIO ) {          ;      } else {          int lab_l; @@ -1693,8 +1784,6 @@ void wControlSetContext(      b->data = context;  } -static int controlHiliteWidth = 5; -static int controlHiliteWidth2 = 3;  void wControlHilite(      wControl_p b,      wBool_t hilite) @@ -1702,12 +1791,13 @@ void wControlHilite(      HDC hDc;      HPEN oldPen, newPen;      int oldMode; +	LOGBRUSH logBrush = { BS_SOLID, CONTROLHILITECOLOR, (ULONG_PTR)NULL };      if (b == NULL) {          return;      } -    if (!IsWindowVisible(b->parent->hWnd)) { +    if (!IsWindowVisible(b->parent->hWnd)) {	          return;      } @@ -1716,14 +1806,18 @@ void wControlHilite(      }      hDc = GetDC(b->parent->hWnd); -    newPen = CreatePen(PS_SOLID, controlHiliteWidth, RGB(0,0,0)); +	newPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND | PS_JOIN_BEVEL, +						  CONTROLHILITEWIDTH, +						  &logBrush, +						  0, +						  NULL);      oldPen = SelectObject(hDc, newPen);      oldMode = SetROP2(hDc, R2_NOTXORPEN); -    MoveTo(hDc, b->x-controlHiliteWidth2, b->y-controlHiliteWidth2); -    LineTo(hDc, b->x+b->w+controlHiliteWidth2, b->y-controlHiliteWidth2); -    LineTo(hDc, b->x+b->w+controlHiliteWidth2, b->y+b->h+controlHiliteWidth2); -    LineTo(hDc, b->x-controlHiliteWidth2, b->y+b->h+controlHiliteWidth2); -    LineTo(hDc, b->x-controlHiliteWidth2, b->y-controlHiliteWidth2); +	Rectangle(hDc, +		b->x - CONTROLHILITEWIDTH - 1, +		b->y - CONTROLHILITEWIDTH - 1, +		b->x + b->w + CONTROLHILITEWIDTH + 1, +		b->y + b->h + CONTROLHILITEWIDTH + 1);      SetROP2(hDc, oldMode);      SelectObject(hDc, oldPen);      DeleteObject(newPen); @@ -1766,6 +1860,26 @@ void wMessage(      ReleaseDC(w->hWnd, hDc);  } +/** + * Open a document using an external application + *  + * \param file + * \return TRUE on success, FALSE on error + *  + */ +unsigned wOpenFileExternal(char *file) +{ +	HINSTANCE res; + +	res = ShellExecute(mswHWnd, "open", file, NULL, NULL, SW_SHOW); + +	if ((int)res <= 32) { +		wNoticeEx(NT_ERROR, "Error when opening file!", "Cancel", NULL); +		return(FALSE); +	} + +	return(TRUE); +}  void wExit(int rc)  { @@ -2040,12 +2154,22 @@ int wNotice3(      }  } +/** + * Show help text for the given topic.  + * + * \param  topic The topic. if NULL the index page is shown. + */  void wHelp(      const char * topic)  {      char *pszHelpTopic;      HWND hwndHelp; +	char *theTopic = "index"; + +	if (topic) { +		theTopic = topic; +	}      if (!helpInitted) {          HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie) ; @@ -2054,9 +2178,9 @@ void wHelp(      /*	             "c:\\help.chm::/intro.htm>mainwin", */      /* attention: always adapt constant value (10) to needed number of formatting characters */ -    pszHelpTopic = malloc(strlen(helpFile) + strlen(topic) + 10); +    pszHelpTopic = malloc(strlen(helpFile) + strlen(theTopic) + 10);      assert(pszHelpTopic != NULL); -    sprintf(pszHelpTopic, "/%s.html", topic); +    sprintf(pszHelpTopic, "/%s.html", theTopic);      hwndHelp = HtmlHelp(mswHWnd, helpFile, HH_DISPLAY_TOPIC,                          (DWORD_PTR)pszHelpTopic); @@ -2068,6 +2192,8 @@ void wHelp(  } + +  void doHelpMenu(void * context)  {      HH_FTS_QUERY ftsQuery; @@ -2092,6 +2218,13 @@ void doHelpMenu(void * context)          HtmlHelp(mswHWnd, helpFile, HH_DISPLAY_SEARCH,(DWORD)&ftsQuery);          break; + +    case 3: /*Context*/ +    	const char * topic; +    	topic = GetCurCommandName(); +    	wHelp(topic); +    	break; +      default:          return;      } @@ -2099,11 +2232,16 @@ void doHelpMenu(void * context)      helpInitted = TRUE;  } +void wDoAccelHelp(wAccelKey_e key, void * context) { +	doHelpMenu(context); +} +  void wMenuAddHelp(      wMenu_p m)  { -    wMenuPushCreate(m, NULL, "&Contents", 0, doHelpMenu, (void*)1); -    wMenuPushCreate(m, NULL, "&Search for Help on...", 0, doHelpMenu, (void*)2); +    wMenuPushCreate(m, NULL, _("&Contents"), 0, doHelpMenu, (void*)1); +    wMenuPushCreate(m, NULL, _("&Search for Help on..."), 0, doHelpMenu, (void*)2); +    wMenuPushCreate(m, NULL, _("Co&mmand Context Help"), 0, doHelpMenu, (void*)3);  } @@ -2326,6 +2464,24 @@ struct wFilSel_t {  #define SELECTEDFILENAME_BUFFERSIZE	(8*1024)	/**<estimated size in case all param files are selected */ +char * +GetImageFileFormats(void) +{ +	char *filter = malloc(2048); +	char *current = filter; +	char *message; + +	for (int i = 0; i < sizeof(filterImageFiles) / sizeof(filterImageFiles[0]); i += 2) { +		message = gettext(filterImageFiles[i]); +		strcpy(current, message); +		current += strlen(message) + 1; +		strcpy(current, filterImageFiles[i + 1]); +		current += strlen(current) + 1; +	} +	*current = '\0'; +	return(filter); +} +  /**   * Run the file selector. After the selector is finished an array of filenames is   * created. Each filename will be fully qualified. The array and the number of @@ -2356,11 +2512,16 @@ int wFilSelect(              strcmp(dirName, ".") == 0) {          dirName = wGetUserHomeDir();      } -      memset(&ofn, 0, sizeof ofn);      ofn.lStructSize = sizeof ofn;      ofn.hwndOwner = mswHWnd; -    ofn.lpstrFilter = fs->extList; +	if (fs->option == FS_PICTURES) { +		ofn.lpstrFilter = GetImageFileFormats(); +	} +	else { +		ofn.lpstrFilter = fs->extList; +	} +      ofn.nFilterIndex = 0;      selFileName = malloc(SELECTEDFILENAME_BUFFERSIZE);      memset(selFileName, '\0', SELECTEDFILENAME_BUFFERSIZE); @@ -2599,6 +2760,23 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)      wAccelKey_e extChar;      switch (message) { +	case WM_GETMINMAXINFO: +		LPMINMAXINFO pMMI = (LPMINMAXINFO)lParam; +		inx = GetWindowWord(hWnd, 0); + +		if (inx >= CONTROL_BASE && inx <= controlMap_da.cnt) { +			w = (wWin_p)controlMap(inx - CONTROL_BASE).b; +			if (w != NULL) { +				if (w->validGeometry) { +					pMMI->ptMaxTrackSize.x = w->max_width; +					pMMI->ptMaxTrackSize.y = w->max_height; +					pMMI->ptMinTrackSize.x = w->min_width; +					pMMI->ptMinTrackSize.y = w->min_height; +				} +			} +		} +		return(0); +      case WM_MOUSEWHEEL:          inx = GetWindowWord(hWnd, 0);          b = getControlFromCursor(hWnd, NULL); @@ -2614,22 +2792,6 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)      case WM_DRAWITEM:      case WM_COMMAND:      case WM_MEASUREITEM: -    case WM_NOTVALID: -        if (WCMD_PARAM_ID == IDM_DOHELP) { -            b = getControlFromCursor(hWnd, NULL); -            closeBalloonHelp(); - -            if (!b) { -                return 0L; -            } - -            if (b->helpStr) { -                wHelp(b->helpStr); -            } - -            return 0L; -        } -          closeBalloonHelp();          if (WCMD_PARAM_ID < CONTROL_BASE || WCMD_PARAM_ID > (WPARAM)controlMap_da.cnt) { @@ -2913,26 +3075,26 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)      case WM_SETCURSOR:          /*if (any buttons down)          	break;*/ -        wSetCursor(curCursor); +        wSetCursor(NULL, curCursor);          if (!mswAllowBalloonHelp) { -            break; +            return TRUE;          }          if (IsIconic(mswHWnd)) { -            break; +            return TRUE;          }          b = getControlFromCursor(hWnd, NULL);          if (b == balloonControlButton) { -            break; +            return TRUE;          }          if (/*(!IsWindowEnabled(hWnd))*/ GetActiveWindow() != hWnd ||                                           (!b) || b->type == B_DRAW || b->helpStr == NULL) {              closeBalloonHelp(); -            break; +            return TRUE;          }          if (b != balloonHelpButton) { @@ -2940,19 +3102,19 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)          }          if (balloonHelpState != balloonHelpIdle) { -            break; +            return TRUE;          }          balloonHelpTimer = SetTimer(mswHWnd, BALLOONHELP_TIMER,                                      balloonHelpTimeOut, NULL);          if (balloonHelpTimer == (UINT)0) { -            break; +            return TRUE;          }          balloonHelpState = balloonHelpWait;          balloonHelpButton = b; -        break; +        return TRUE;      case WM_SYSCOMMAND:          inx = GetWindowWord(hWnd, 0); @@ -3211,13 +3373,13 @@ static BOOL InitApplication(HINSTANCE hinstCurrent)          return FALSE;      } -    wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; +    wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLKS;      wc.lpfnWndProc = mswDrawPush;      wc.lpszClassName = mswDrawWindowClassName;      wc.cbWndExtra = 4;      if (!RegisterClass(&wc)) { -        mswFail("RegisterClass(drawClass)"); +		mswFail("RegisterClass(drawClass)");          return FALSE;      } @@ -3238,8 +3400,6 @@ int PASCAL WinMain(HINSTANCE hinstCurrent, HINSTANCE hinstPrevious,      HDC hDc;      char **argv;      int argc; -    TEXTMETRIC tm; -    DWORD dw;  	if (!hinstPrevious) {  		if (!InitApplication(hinstCurrent)) { @@ -3264,10 +3424,6 @@ int PASCAL WinMain(HINSTANCE hinstCurrent, HINSTANCE hinstPrevious,          mswScale = 1.0;      } -    GetTextMetrics(hDc, &tm); -    mswEditHeight = tm.tmHeight + 8; -    dw = GetTextExtent(hDc, "AXqypj", 6); -    mswEditHeight = HIWORD(dw)+2;      ReleaseDC(0, hDc);      mswCreateCheckBitmaps();      /* diff --git a/app/wlib/mswlib/mswmsg.c b/app/wlib/mswlib/mswmsg.c index 4a21921..6445299 100644 --- a/app/wlib/mswlib/mswmsg.c +++ b/app/wlib/mswlib/mswmsg.c @@ -42,6 +42,7 @@ static void repaintMessage(  	HFONT hFont;  	LOGFONT msgFont;  	double scale = 1.0; +	TEXTMETRIC textMetrics;  	hDc = GetDC( hWnd ); @@ -74,13 +75,15 @@ static void repaintMessage(  			hFont = SelectObject( hDc, mswLabelFont );  	} +	GetTextMetrics(hDc, &textMetrics); +  	rect.bottom = (long)(bm->y+( bm->h ));  	rect.right = (long)(bm->x+( scale * bm->w )); -	rect.top = bm->y; +	rect.top = bm->y+1;  	rect.left = bm->x;  	SetBkColor( hDc, GetSysColor( COLOR_BTNFACE ) ); -	ExtTextOut( hDc, bm->x, bm->y, ETO_CLIPPED|ETO_OPAQUE, &rect, bm->message, strlen( bm->message ), NULL ); +	ExtTextOut( hDc, bm->x, bm->y + ((bm->h + 2 - textMetrics.tmHeight) / 2), ETO_CLIPPED|ETO_OPAQUE, &rect, bm->message, strlen( bm->message ), NULL );  	if( scale != 1.0 )  		/* in case we did create a new font earlier, delete it now */ @@ -138,7 +141,7 @@ wPos_t wMessageGetHeight( long flags )  	if( flags & BM_SMALL )  		scale = SCALE_SMALL; -	return((wPos_t)((mswEditHeight - 4) * scale )); +	return((wPos_t)((mswEditHeight) * scale ));  #endif  } diff --git a/app/wlib/mswlib/mswpref.c b/app/wlib/mswlib/mswpref.c index eaa39fe..201171a 100644 --- a/app/wlib/mswlib/mswpref.c +++ b/app/wlib/mswlib/mswpref.c @@ -5,6 +5,7 @@  #include <commdlg.h>  #include <math.h>  #include <stdio.h> +#include "misc.h"  #include "mswint.h"  #include <shlobj.h>  #include <Shlwapi.h> diff --git a/app/wlib/mswlib/mswprint.c b/app/wlib/mswlib/mswprint.c index 91f05ea..13756c7 100644 --- a/app/wlib/mswlib/mswprint.c +++ b/app/wlib/mswlib/mswprint.c @@ -27,7 +27,7 @@ struct tagPD printDlg;  #endif  static int printStatus = FALSE;  static DOCINFO docInfo; -static double pageSizeW = 8.5, pageSizeH = 11.0; +static double tBorder = 0.0, rBorder = 0.0, bBorder = 0.0, lBorder = 0.0;  static double physSizeW = 8.5, physSizeH = 11.0;  static int pageCount = -1; @@ -66,10 +66,16 @@ void getPageDim( HDC hDc )  	size_h = GetDeviceCaps( hDc, VERTSIZE );  	print_d.w = res_w = GetDeviceCaps( hDc, HORZRES );  	print_d.h = res_h = GetDeviceCaps( hDc, VERTRES ); +	double pageSizeW, pageSizeH;  	pageSizeW = ((double)res_w)/print_d.wFactor;  	pageSizeH = ((double)res_h)/print_d.hFactor;  	physSizeW = ((double)dims.x)/print_d.wFactor;  	physSizeH = ((double)dims.y)/print_d.hFactor; +	// Get Borders/Margins - offs are the top, left borders +	lBorder = ((double)offs.x)/print_d.hFactor; +	tBorder = ((double)offs.y)/print_d.hFactor; +	rBorder = physSizeW-pageSizeW-lBorder; +	bBorder = physSizeH-pageSizeH-tBorder;  }  static wBool_t printInit( void ) @@ -83,6 +89,7 @@ static wBool_t printInit( void )  		return printerOk;  	}  	initted = TRUE; +	memset(&printDlg, 0, sizeof printDlg);  	printDlg.lStructSize = sizeof printDlg;  	printDlg.hwndOwner = NULL;  	printDlg.Flags = PD_RETURNDC|PD_RETURNDEFAULT; @@ -194,16 +201,36 @@ void wPrintSetup( wPrintSetupCallBack_p callback )  	}  } +const char* wPrintGetName() +{ +	static char sPrinterName[100]; +	HANDLE hDevNames = printDlg.hDevNames; +	DEVNAMES* pDevNames = GlobalLock(hDevNames); +	if (pDevNames == NULL) { +		strcpy(sPrinterName, "Printer"); +	} +	else { +		strncpy(sPrinterName, (char*)pDevNames + pDevNames->wDeviceOffset, sizeof sPrinterName - 1); +		sPrinterName[sizeof sPrinterName - 1] = '\0'; +	} +	GlobalUnlock( hDevNames ); +	return sPrinterName; +} -void wPrintGetPageSize( double *w, double *h ) +void wPrintGetMargins( +	double * tMargin, +	double * rMargin, +	double * bMargin, +	double * lMargin )  { -	printInit(); -	*w = pageSizeW; -	*h = pageSizeH; +	if ( tMargin ) *tMargin = tBorder; +	if ( rMargin ) *rMargin = rBorder; +	if ( bMargin ) *bMargin = bBorder; +	if ( lMargin ) *lMargin = lBorder;  } -void wPrintGetPhysSize( double *w, double *h ) +void wPrintGetPageSize( double *w, double *h )  {  	printInit();  	*w = physSizeW; @@ -378,10 +405,3 @@ wBool_t wPrintNewMargin( const char * name, double t, double b, double l, double  {  	return TRUE;  } - -void wPrintSetCallBacks( -		wAddPrinterCallBack_p newPrinter, -		wAddMarginCallBack_p newMargin, -		wAddFontAliasCallBack_p newFontAlias ) -{ -} diff --git a/app/wlib/mswlib/mswsplash.c b/app/wlib/mswlib/mswsplash.c index 47df6b7..172b563 100644 --- a/app/wlib/mswlib/mswsplash.c +++ b/app/wlib/mswlib/mswsplash.c @@ -204,8 +204,11 @@ wCreateSplash( char *appname, char *appver )  	/* create the title string */	  	pszBuf = malloc( strlen( appname ) + strlen( appver ) + 2 ); -	if( !pszBuf ) -		return( 0 ); +	if (!pszBuf) { +		GlobalUnlock(hgbl); +		GlobalFree(hgbl); +		return(0); +	}  	sprintf( pszBuf, "%s %s", appname, appver );  	lpw  += 1+MultiByteToWideChar (CP_ACP, 0, pszBuf, -1, (LPWSTR)lpw, 50); @@ -226,7 +229,6 @@ wCreateSplash( char *appname, char *appver )      GlobalUnlock(hgbl);       hSplash = CreateDialogIndirectParam( mswHInst, (LPDLGTEMPLATE) hgbl,           mswHWnd, (DLGPROC)SplashDlgProc, (LPARAM)hBmp );  -	GetLastError();  	/* free allocated memory */  	GlobalFree(hgbl);      diff --git a/app/wlib/mswlib/mswtext.c b/app/wlib/mswlib/mswtext.c index 293e2b4..0a0ce88 100644 --- a/app/wlib/mswlib/mswtext.c +++ b/app/wlib/mswlib/mswtext.c @@ -137,6 +137,9 @@ void wTextAppend(      if (b->option&BO_READONLY) {          SendMessage(b->hWnd, EM_SETREADONLY, 1, 0L);      } + +	// scroll to bottom of text box +	SendMessage(b->hWnd, EM_LINESCROLL, 0, 10000L);  } @@ -247,42 +250,54 @@ wBool_t wTextGetModified(      return (wBool_t)rc;  } +/** + * Get the size of the text in the text control including terminating '\0'. Note that + * the text actually might be shorter if the text includes CRs. + *  + * \param b IN text control + * \return required buffer size + */  int wTextGetSize(      wText_p b)  { -    int lc, l, len=0; -    lc = (int)SendMessage(b->hWnd, EM_GETLINECOUNT, 0, 0L); +	int len; -    for (l=0; l<lc ; l++) { -        int charIndex = (int)SendMessage(b->hWnd, EM_LINEINDEX, l, 0L); -        len += (int)SendMessage(b->hWnd, EM_LINELENGTH, charIndex, 0L) + 1; -    } - -    if (len == 1) { -        len = 0; -    } +	len = GetWindowTextLength(b->hWnd); -    return len; +    return len + 1;  } +/**  + * Get the text from a textentry. The buffer must be large enough for the text and + * the terminating \0. + * In case the string contains carriage returns these are removed. The returned string + * will be shortened accordingly.  + * To get the complete contents the buffer size must be equal or greater then the return + * value of wTextGetSize() + *  + * \param b IN text entry + * \param t IN/OUT buffer for text + * \param s IN size of buffer  + */ +   void wTextGetText(      wText_p b,      char * t,      int s)  { -    int lc, l, len; -    s--; -    lc = (int)SendMessage(b->hWnd, EM_GETLINECOUNT, 0, 0L); - -    for (l=0; l<lc && s>=0; l++) { -        *(WORD*)t = s; -        len = (int)SendMessage(b->hWnd, EM_GETLINE, l, (LPARAM)t); -        t += len; -        *t++ = '\n'; -        s -= len+1; -    } - -    *(t - 1) = '\0';		// overwrite the last \n added +	char *buffer = malloc(s); +	char *ptr = buffer; +	GetWindowText(b->hWnd, buffer, s); + +	// remove carriage returns +	while (*ptr) { +		if (*ptr != '\r') { +			*t = *ptr; +			t++; +		} +		ptr++; +	} +	free(buffer);  } diff --git a/app/wlib/mswlib/simple-gettext.c b/app/wlib/mswlib/simple-gettext.c index d213fc3..412eece 100644 --- a/app/wlib/mswlib/simple-gettext.c +++ b/app/wlib/mswlib/simple-gettext.c @@ -148,8 +148,9 @@ utf8_to_native( char *str, unsigned int len, int dummy )  		/* 2. convert from UTF-8 to system codepage */  		WideCharToMultiByte(CP_ACP, 0, (LPWSTR)buf, wcharLen, resBuffer, len + 1, NULL, NULL ); -		free( buf ); +  	} +	free(buf);  	return( resBuffer );	  } diff --git a/app/wlib/mswlib/unittest/CMakeLists.txt b/app/wlib/mswlib/unittest/CMakeLists.txt new file mode 100644 index 0000000..b91c1ff --- /dev/null +++ b/app/wlib/mswlib/unittest/CMakeLists.txt @@ -0,0 +1,11 @@ +# build unit tests for the xtrkcad Windows library + +add_executable(utf8test +  		utf8test.c +		../utf8conv.c +		) + +target_link_libraries(utf8test +  		 ${LIBS}) + +add_test(UTF8ConversionTest utf8test) diff --git a/app/wlib/mswlib/unittest/utf8test.c b/app/wlib/mswlib/unittest/utf8test.c new file mode 100644 index 0000000..5b00371 --- /dev/null +++ b/app/wlib/mswlib/unittest/utf8test.c @@ -0,0 +1,65 @@ +/** \file utf8test.c +* Unit tests for utf 8 conversion routines on Windows +*/ + +#include <setjmp.h> +#include <stdbool.h> +#include <string.h> + +#include <cmocka.h> + +#include <wlib.h> + +#define SIMPLEASCIITEXT "The quick brown fox jumps over the lazy dog." +#define UMLAUTTEXT "äöüÄÖÜß" + +static void +ASCIIText(void **state) +{ +	char output[100]; +	char result[100]; +	bool success; +	(void)state; + +	success = wSystemToUTF8(SIMPLEASCIITEXT, output, 100); +	assert_true((void *)success); + +	success = wUTF8ToSystem(output, result, 100); +	assert_true((void *)success); + +	assert_false(strcmp(SIMPLEASCIITEXT, result)); +} + +static void +Umlauts(void **state) +{ +	char output[100]; +	char result[100]; +	bool success; +	(void)state; + +	success = wIsUTF8(UMLAUTTEXT); +	assert_false((void *)success); + +	success = wSystemToUTF8(UMLAUTTEXT, output, 100); +	assert_true((void *)success); + +	success = wIsUTF8(output); +	assert_true((void *)success); + +	success = wUTF8ToSystem(output, result, 100); +	assert_true((void *)success); + +	assert_false(strcmp(UMLAUTTEXT, result)); +} + + +int main(void) +{ +    const struct CMUnitTest tests[] = { +		cmocka_unit_test(ASCIIText), +		cmocka_unit_test(Umlauts), +    }; + +    return cmocka_run_group_tests(tests, NULL, NULL); +}
\ No newline at end of file diff --git a/app/wlib/mswlib/utf8conv.c b/app/wlib/mswlib/utf8conv.c new file mode 100644 index 0000000..62ada76 --- /dev/null +++ b/app/wlib/mswlib/utf8conv.c @@ -0,0 +1,210 @@ +/** + * \file utf8conv.c. + * + * UTF-8 conversion functions + */ + +/*  XTrkCad - Model Railroad CAD + *  Copyright (C) 2020 Martin Fischer + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <malloc.h> +#include <stdbool.h> +#include <string.h> + +#include <Windows.h> + +#include <wlib.h> + +/** + * Convert system codepage to UTF 8 + * + * \param 		   inString		   The input string. + * \param [in,out] outString	   The output string buffer. + * \param 		   outStringLength Length of the output buffer + * + * \returns FALSE if it fails. + */ + +bool +wSystemToUTF8(const char *inString, char *outString, unsigned outStringLength) +{ +    unsigned int cnt = 2 * (strlen(inString) + 1); +    char *tempBuffer = malloc(cnt); + +    // convert to wide character (UTF16) +    MultiByteToWideChar(CP_ACP, +                        0, +                        inString, +                        -1, +                        (LPWSTR)tempBuffer, +                        cnt); + +    // convert from wide char to UTF-8 +    WideCharToMultiByte(CP_UTF8, +                        0, +                        (LPCWCH)tempBuffer, +                        -1, +                        (LPSTR)outString, +                        outStringLength, +                        NULL, +                        NULL); + +    free(tempBuffer); +    return true; +} + +/** + * Convert from UTF-8 to system codepage + * + * \param 		   inString		   The input string. + * \param [in,out] outString	   the output string. + * \param 		   outStringLength Length of the output buffer. + * + * \returns True if it succeeds, false if it fails. + */ + +bool +wUTF8ToSystem(const char *inString, char *outString, unsigned outStringLength) +{ +    unsigned int cnt = 2 * (strlen(inString) + 1); +    char *tempBuffer = malloc(cnt); + +    // convert to wide character (UTF16) +    MultiByteToWideChar(CP_UTF8, +                        0, +                        inString, +                        -1, +                        (LPWSTR)tempBuffer, +                        cnt); + + +    cnt = WideCharToMultiByte(CP_ACP, +                              0, +                              (LPCWCH)tempBuffer, +                              -1, +                              (LPSTR)outString, +                              0L, +                              NULL, +                              NULL); + +    if (outStringLength <= cnt) { +        return (false); +    } + +    // convert from wide char to system codepage +    WideCharToMultiByte(CP_ACP, +                        0, +                        (LPCWCH)tempBuffer, +                        -1, +                        (LPSTR)outString, +                        outStringLength, +                        NULL, +                        NULL); + +    free(tempBuffer); +    return true; +} + +/** + * Is passed string in correct UTF-8 format? + * Taken from https://stackoverflow.com/questions/1031645/how-to-detect-utf-8-in-plain-c + * + * \param  string The string to check. + * + * \returns True if UTF 8, false if not. + */ + +bool wIsUTF8(const char * string) +{ +    if (!string) { +        return 0; +    } + +    const unsigned char * bytes = (const unsigned char *)string; +    while (*bytes) { +        if ((// ASCII +                    // use bytes[0] <= 0x7F to allow ASCII control characters +                    bytes[0] == 0x09 || +                    bytes[0] == 0x0A || +                    bytes[0] == 0x0D || +                    (0x20 <= bytes[0] && bytes[0] <= 0x7E) +                ) +           ) { +            bytes += 1; +            continue; +        } + +        if ((// non-overlong 2-byte +                    (0xC2 <= bytes[0] && bytes[0] <= 0xDF) && +                    (0x80 <= bytes[1] && bytes[1] <= 0xBF) +                ) +           ) { +            bytes += 2; +            continue; +        } + +        if ((// excluding overlongs +                    bytes[0] == 0xE0 && +                    (0xA0 <= bytes[1] && bytes[1] <= 0xBF) && +                    (0x80 <= bytes[2] && bytes[2] <= 0xBF) +                ) || +                (// straight 3-byte +                    ((0xE1 <= bytes[0] && bytes[0] <= 0xEC) || +                     bytes[0] == 0xEE || +                     bytes[0] == 0xEF) && +                    (0x80 <= bytes[1] && bytes[1] <= 0xBF) && +                    (0x80 <= bytes[2] && bytes[2] <= 0xBF) +                ) || +                (// excluding surrogates +                    bytes[0] == 0xED && +                    (0x80 <= bytes[1] && bytes[1] <= 0x9F) && +                    (0x80 <= bytes[2] && bytes[2] <= 0xBF) +                ) +           ) { +            bytes += 3; +            continue; +        } + +        if ((// planes 1-3 +                    bytes[0] == 0xF0 && +                    (0x90 <= bytes[1] && bytes[1] <= 0xBF) && +                    (0x80 <= bytes[2] && bytes[2] <= 0xBF) && +                    (0x80 <= bytes[3] && bytes[3] <= 0xBF) +                ) || +                (// planes 4-15 +                    (0xF1 <= bytes[0] && bytes[0] <= 0xF3) && +                    (0x80 <= bytes[1] && bytes[1] <= 0xBF) && +                    (0x80 <= bytes[2] && bytes[2] <= 0xBF) && +                    (0x80 <= bytes[3] && bytes[3] <= 0xBF) +                ) || +                (// plane 16 +                    bytes[0] == 0xF4 && +                    (0x80 <= bytes[1] && bytes[1] <= 0x8F) && +                    (0x80 <= bytes[2] && bytes[2] <= 0xBF) && +                    (0x80 <= bytes[3] && bytes[3] <= 0xBF) +                ) +           ) { +            bytes += 4; +            continue; +        } + +        return false; +    } + +    return true; +}
\ No newline at end of file | 
