diff options
Diffstat (limited to 'app/wlib/mswlib')
26 files changed, 12287 insertions, 0 deletions
diff --git a/app/wlib/mswlib/CMakeLists.txt b/app/wlib/mswlib/CMakeLists.txt new file mode 100644 index 0000000..0c69610 --- /dev/null +++ b/app/wlib/mswlib/CMakeLists.txt @@ -0,0 +1,39 @@ +FILE(GLOB HEADERS *.h) + +SET(SOURCES +# checksum.c + getopt.c + mswbox.c + mswbutt.c + mswbitmap.c + mswchksm.c + mswchoic.c + mswcolor.c + mswdraw.c + mswedit.c + mswlines.c + mswlist.c + mswmenu.c + mswmisc.c + mswmsg.c + mswpref.c + mswprint.c + mswsplash.c + mswtext.c + gwin32.c + simple-gettext.c + ) + +INCLUDE_DIRECTORIES(${XTrkCAD_BINARY_DIR}) +# INCLUDE_DIRECTORIES(${XTRKCAD_BINARY_DIR}) + +IF(XTRKCAD_USE_GETTEXT) + IF(WIN32) + ADD_DEFINITIONS(-DUSE_SIMPLE_GETTEXT ) + ENDIF(WIN32) +ENDIF(XTRKCAD_USE_GETTEXT) + +ADD_LIBRARY(xtrkcad-wlib ${HEADERS} ${SOURCES}) + +TARGET_LINK_LIBRARIES(xtrkcad-wlib Htmlhelp msimg32 shlwapi) + diff --git a/app/wlib/mswlib/ChangeLog b/app/wlib/mswlib/ChangeLog new file mode 100644 index 0000000..84c17a7 --- /dev/null +++ b/app/wlib/mswlib/ChangeLog @@ -0,0 +1,146 @@ +Apr 28, 2010 + FIX: Daniel Spagnol + mswmisc.c: now, wGetAppLibDir can be called before wWinMainCreate is + called. + +Jan 09, 2010 + ENH: Martin Fischer + mswmisc.c: get command line parameter handling correct + plus some refactoring + +Dec 12, 2009 + FIX: Martin Fischer + mswmisc.c: minor refactoring to stay compatible with the + work on gtkwindow.c + +Sep 20. 2009 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + CMakeLists.txt, mswbitmap.c, mswmisc.c, mswint.h: + new source file for bitmap functions, added bitmap + control to controls available to the application + +Sep 02, 2009 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswbutt.c, mswint.h, mswlist.c mswmisc.c: + improved XPM reading including true transparency + +Aug 16, 2009 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + gwin32.c mswchoic.c mswint.h simple-gettext.c CMakeLists.txt: + add simple gettext support + +Jul 24, 2009 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c: correct initialization for argv, add option + to select configuration file, remove obsolete Win16 code + +Jul 10, 2009 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c: initialize the argument array properly + CMakeLists.txt, getopt.c: add getopt() + +Version 4.0.3a +============== + +Jun 05, 2009 + FIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c: GPF when loading XPM icons fixed + +May 28, 2009 + FIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c: wrong options for wNotice fixed + +May 15, 2009 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswdraw.c, mswmisc.c, mswpref.c: more message boxes with icon + + May 08, 2009 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c, wlib.h: add new message box with icon + +Sep 05, 2008 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c: enhance look of tooltip + +Jul 11, 2008 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswchoic.c: i18n support + mswmenu.c, mswmisc.c: code cleanup and added comments + +Jul 10, 2008 + ENH: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c: allow user to cancel window close request + +Jun 12, 2008 + FIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswmsg.c: redraw problem for large font fixed + +Apr 05, 2008 + IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc,.c mswint.c: improved XPM support + +Mar 29, 2008 + IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswbutt.c: new look for toolbar buttons + +Mar 17, 2008 + FIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswchoic.c: Label size was not calculated correctly for radio button + options. + +Feb 23,2008 + FIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswpref.c: Create the correct full path for shared data directory + +Jan 24,2008 + FIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswdraw.c, mswmisc.c: fixed some compiler warnings + +Jan 28, 2008 + FIX: Mikko Nissinen <mni77@users.sourceforge.net> + mswmisc.c: Dynamically allocate and form some global translatable + strings. + +Jan 24,2008 + IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswpref.c: increase floting point precision when storing floats in INI + file + +Jan 22, 2008 + ENH: Mikko Nissinen <mni77@users.sourceforge.net> + mswmisc.c: WinMain(): Free user locale before exit. + +Dec 16, 2007 + IMPROVMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswpref.c: use XTrackCad as directory name for configuration files + +Aug 03, 2007 + IMPROVMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c: use HTML Help as the help system + +Jul 22, 2007 + IMPROVMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswdraw.c, mswmisc.c: added support for mouse wheel in + the drawing area + +Jun 17, 2007 + IMPROVMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswpref.c: added wGetUserHomeDir() + +Jun, 16 2007 + IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net> + mswpref.c working directory is in the user profile directory tree now + +Feb, 05th 2007 + BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c fixed protection fault when pressing ESC in describe dialog + +Feb, 04th 2007 + BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net> + mswmisc.c fixed protection fault when Tabbing through describe dialog + See xtrkcad-fork Bug 1651117 + +Oct, 13 2006 mswmisc.c + BUGFIX Bob Blackwell + Fixed a problem with 'No' and 'Cancel' buttons being mixed up + diff --git a/app/wlib/mswlib/checksum.c b/app/wlib/mswlib/checksum.c new file mode 100644 index 0000000..f19d15b --- /dev/null +++ b/app/wlib/mswlib/checksum.c @@ -0,0 +1,42 @@ +#include "mswchksm.c" +#include <stdlib.h> + +int main( int argc, char *argv[] ) +{ + int set; + FILE * fp; + long FileSize; + unsigned short sum16computed, sum16stored = 0xb8dd; + unsigned long sum32computed, sum32stored = 0xa25ce7ac; + long sum32off; + if (argc < 2) { + fprintf( stderr, "Usage: %s [-s] file.exe\n", argv[0] ); + exit(1); + } + if (argc > 2) { + set = 1; + fp = openfile( argv[2], "r+b", &FileSize ); + } else { + set = 0; + fp = openfile( argv[1], "rb", &FileSize ); + } + if (fp == NULL) + exit(1); + + fprintf( stderr, "File Size = %ld (%lx)\n", FileSize, FileSize ); + sum16computed = mswCheck16( fp, FileSize, &sum16stored ); + if (!mswCheck32( fp, FileSize, &sum32off, &sum32computed, &sum32stored )) + fprintf( stderr, "mswCheck32 error\n" ); + fprintf( stderr, "sum16: stored = %x, computed = %x, sum = %x, expected FFFF\n", sum16stored, sum16computed, sum16stored+sum16computed ); + fprintf( stderr, "sum32: stored = %lx, computed = %lx, expected %lx\n", sum32stored, sum32computed, sum32stored ); + if (set) { + fseek( fp, 0x12, SEEK_SET ); + sum16computed = 0xFFFF - sum16computed; + fwrite( &sum16computed, sizeof sum16computed, 1, fp ); + fseek( fp, sum32off, SEEK_SET ); + /*fwrite( &sum32computed, sizeof sum32computed, 1, fp );*/ + fflush( fp ); + } + fclose(fp); + exit(0); +} diff --git a/app/wlib/mswlib/dynarr.h b/app/wlib/mswlib/dynarr.h new file mode 100644 index 0000000..5bd7a8e --- /dev/null +++ b/app/wlib/mswlib/dynarr.h @@ -0,0 +1,40 @@ +typedef struct { + int cnt; + int max; + void * ptr; + } dynArr_t; + +#define DYNARR_APPEND(T,DA,INCR) \ + { if ((DA).cnt >= (DA).max) { \ + (DA).max += INCR; \ + (DA).ptr = realloc( (DA).ptr, (DA).max * sizeof *(T*)NULL ); \ + if ( (DA).ptr == NULL ) \ + abort(); \ + } \ + (DA).cnt++; } +#define DYNARR_ADD(T,DA,INCR) DYNARR_APPEND(T,DA,INCR) + +#define DYNARR_LAST(T,DA) \ + (((T*)(DA).ptr)[(DA).cnt-1]) +#define DYNARR_N(T,DA,N) \ + (((T*)(DA).ptr)[N]) +#define DYNARR_RESET(T,DA) \ + (DA).cnt=0 +#define DYNARR_SET(T,DA,N) \ + { if ((DA).max < N) { \ + (DA).max = N; \ + (DA).ptr = realloc( (DA).ptr, (DA).max * sizeof *(T*)NULL ); \ + if ( (DA).ptr == NULL ) \ + abort(); \ + } \ + (DA).cnt = 0; } + + +#ifdef WINDOWS +#ifndef WIN32 +#define FAR _far +#endif +#define M_PI 3.14159 +#define strcasecmp _stricmp +#else +#endif diff --git a/app/wlib/mswlib/getopt.c b/app/wlib/mswlib/getopt.c new file mode 100644 index 0000000..888f5f8 --- /dev/null +++ b/app/wlib/mswlib/getopt.c @@ -0,0 +1,87 @@ +/*---------------------------------------------------------------------- + + Replacement for Unix "getopt()", for DOS/Windows/etc. + + getopt.c 1.3 2003/09/17 16:17:59 + + Copyright (C) 1998, 2003 by David A. Hinds -- All Rights Reserved + + This file is part of ASPEX. + + ASPEX 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. + + ASPEX 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 ASPEX; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +----------------------------------------------------------------------*/ + +#include "string.h" +#include "stdio.h" +#include "getopt.h" + +#ifdef WINDOWS +#define OPTCHAR '/' +#else +#define OPTCHAR '-' +#endif + +char *optarg; +int optind = 1, opterr, optopt; + +int getopt(int argc, char *argv[], const char *optstring) +{ + static int pos = 0; + char *str; + + if (pos == 0) { + if ((optind >= argc) || (*argv[optind] != OPTCHAR)) + return EOF; + pos = 1; + if (argv[optind][pos] == '\0') + return EOF; + } + + str = strchr(optstring, argv[optind][pos]); + if (str == NULL) { + optopt = argv[optind][pos]; + if (opterr) + fprintf(stderr, "%s: illegal option -- %c\n", argv[0], + optopt); + return '?'; + } + + if (str[1] == ':') { + if (argv[optind][pos+1] != '\0') { + optarg = &argv[optind][pos+1]; + return *str; + } + optind++; + if (optind >= argc) { + optopt = *str; + if (opterr) + fprintf(stderr, "%s: option requires an argument -- %c\n", + argv[0], optopt); + return '?'; + } + optarg = argv[optind]; + optind++; pos = 0; + return *str; + } + else { + pos++; + if (argv[optind][pos] == '\0') { + optind++; + pos = 0; + } + return *str; + } +} diff --git a/app/wlib/mswlib/gwin32.c b/app/wlib/mswlib/gwin32.c new file mode 100644 index 0000000..6b0c7f3 --- /dev/null +++ b/app/wlib/mswlib/gwin32.c @@ -0,0 +1,146 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + * + * Ported to standard C by Martin Fischer 2009 + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <wchar.h> +#include <errno.h> + +#define STRICT /* Strict typing, please */ +#include <windows.h> +#undef STRICT +#include <errno.h> +#include <ctype.h> +#if defined(_MSC_VER) || defined(__DMC__) +# include <io.h> +#endif /* _MSC_VER || __DMC__ */ + +#ifndef SUBLANG_SERBIAN_LATIN_BA +#define SUBLANG_SERBIAN_LATIN_BA 0x06 +#endif + +#if _MSC_VER > 1300 + #define stricmp _stricmp + #define strnicmp _strnicmp + #define strdup _strdup +#endif + +/** + * This function gets the current thread locale from Windows - without any + * encoding info - and returns it as a string of the above form for use in forming + * file names etc. The setlocale() function in the Microsoft C library uses locale + * names of the form "English_United States.1252" etc. We want the + * UNIXish standard form "en_US", "zh_TW" etc. The returned string should be + * deallocated with free(). + * + * \return newly-allocated locale name. + */ + +char * +g_win32_getlocale (void) +{ + LCID lcid; + LANGID langid; + char *ev; + char *loc; + int primary, sub; + char iso639[10]; + char iso3166[10]; + const char *script = NULL; + + /* Let the user override the system settings through environment + * variables, as on POSIX systems. Note that in GTK+ applications + * since GTK+ 2.10.7 setting either LC_ALL or LANG also sets the + * Win32 locale and C library locale through code in gtkmain.c. + */ + if (((ev = getenv ("LC_ALL")) != NULL && ev[0] != '\0') + || ((ev = getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0') + || ((ev = getenv ("LANG")) != NULL && ev[0] != '\0')) + return strdup (ev); + + lcid = GetThreadLocale (); + + if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) || + !GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166))) + return strdup ("C"); + + /* Strip off the sorting rules, keep only the language part. */ + langid = LANGIDFROMLCID (lcid); + + /* Split into language and territory part. */ + primary = PRIMARYLANGID (langid); + sub = SUBLANGID (langid); + + /* Handle special cases */ + switch (primary) + { + case LANG_AZERI: + switch (sub) + { + case SUBLANG_AZERI_LATIN: + script = "@Latn"; + break; + case SUBLANG_AZERI_CYRILLIC: + script = "@Cyrl"; + break; + } + break; + case LANG_SERBIAN: /* LANG_CROATIAN == LANG_SERBIAN */ + switch (sub) + { + case SUBLANG_SERBIAN_LATIN: + case 0x06: /* Serbian (Latin) - Bosnia and Herzegovina */ + script = "@Latn"; + break; + } + break; + case LANG_UZBEK: + switch (sub) + { + case SUBLANG_UZBEK_LATIN: + script = "@Latn"; + break; + case SUBLANG_UZBEK_CYRILLIC: + script = "@Cyrl"; + break; + } + break; + } + + loc = malloc( strlen( iso639 ) + strlen( iso3166 ) + (script ? strlen( script ) : 0) + 2 ); + strcpy( loc, iso639 ); + strcat( loc, "_" ); + strcat( loc, iso3166 ); + if( script ) + strcat( loc, script ); + return loc; +} + diff --git a/app/wlib/mswlib/mswbitmap.c b/app/wlib/mswlib/mswbitmap.c new file mode 100644 index 0000000..7371834 --- /dev/null +++ b/app/wlib/mswlib/mswbitmap.c @@ -0,0 +1,508 @@ +/** \file mswbitmap.c + * Bitmap handling functions + * + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswbitmap.c,v 1.1 2009-09-20 14:55:54 m_fischer Exp $ + */ +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2009 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 <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <stdio.h> +#include <assert.h> +#include "mswint.h" +#include "i18n.h" + +#if _MSC_VER > 1300 + #define stricmp _stricmp + #define strnicmp _strnicmp + #define strdup _strdup +#endif + +struct wBitmap_t { + WOBJ_COMMON + }; + +HPALETTE hOldPal; + +HBITMAP mswCreateBitMap( + COLORREF fgCol1, + COLORREF fgCol2, + COLORREF bgCol, + wPos_t w, + wPos_t h, + const char * bits ) +{ + HDC hDc; + HDC hButtDc; + HBRUSH oldBrush, newBrush; + RECT rect; + HBITMAP hBitMap; + HBITMAP hOldBitMap; + const char * byts_p; + int byt, i, j; + + hDc = GetDC( mswHWnd ); + hButtDc = CreateCompatibleDC( hDc ); + hBitMap = CreateCompatibleBitmap( hDc, w, h ); + ReleaseDC( mswHWnd, hDc ); + hOldBitMap = SelectObject( hButtDc, hBitMap ); + if (mswPalette) { + hOldPal = SelectPalette( hButtDc, mswPalette, 0 ); + } + + /*PatBlt( hButtDc, 0, 0, w, h, WHITENESS );*/ + newBrush = CreateSolidBrush( bgCol ); + oldBrush = SelectObject( hButtDc, newBrush ); + rect.top = 0; + rect.left = 0; + rect.bottom = h; + rect.right = w; + FillRect( hButtDc, &rect, newBrush ); + DeleteObject( SelectObject( hButtDc, oldBrush ) ); + + byts_p = bits; + for ( j = 0; j < h; j++ ) { + byt = (0xFF & *byts_p++) | 0x100; + for ( i = 0; i < w; i++ ) { + if (byt == 1) + byt = (0xFF & *byts_p++) | 0x100; + if ( byt & 0x1 ) { + SetPixel( hButtDc, i, j, fgCol1 ); + SetPixel( hButtDc, i+1, j+1, fgCol2 ); + } + byt >>= 1; + } + } + + SelectObject( hButtDc, hOldBitMap ); + DeleteDC( hButtDc ); + return hBitMap; +} + +dynArr_t bitmap_da; +#define controlMap(N) DYNARR_N(controlMap_t,controlMap_da,N) +#define bitmap(N) DYNARR_N(HBITMAP,bitmap_da,N) + +void mswRegisterBitMap( + HBITMAP hBm ) +{ + DYNARR_APPEND( HBITMAP, bitmap_da, 10 ); + bitmap(bitmap_da.cnt-1) = hBm; +} + +void deleteBitmaps( void ) +{ + int inx; + for ( inx=0; inx<bitmap_da.cnt; inx++ ) + DeleteObject( bitmap(inx) ); +} + +/** + * Draw a bitmap to the screen. + * + * \param hDc IN device context + * \param offw IN horizontal offset + * \param offh IN vertical offset + * \param bm IN icon to draw + * \param disabled IN draw in disabled state + * \param color1 IN for two color bitmaps: foreground color enabled state + * \param color2 IN for two color bitmaps: foreground color disabled state + * + */ + +void mswDrawIcon( + HDC hDc, + int offw, + int offh, + wIcon_p bm, + int disabled, + COLORREF color1, + COLORREF color2 ) +{ + int i; + int byt; + BITMAPINFO *bmiInfo; + COLORREF col; + + /* draw the bitmap by dynamically creating a Windows DIB in memory */ + + bmiInfo = malloc( sizeof( BITMAPINFO ) + (bm->colorcnt - 1) * sizeof( RGBQUAD )); + if( !bmiInfo ) { + fprintf( stderr, "could not allocate memory for bmiInfo\n" ); + abort(); + } + + /* initialize bitmap header from XPM information */ + bmiInfo->bmiHeader.biSize = sizeof( bmiInfo->bmiHeader ); + bmiInfo->bmiHeader.biWidth = bm->w; + bmiInfo->bmiHeader.biHeight = bm->h; + bmiInfo->bmiHeader.biPlanes = 1; + if( bm->type == mswIcon_bitmap ) + bmiInfo->bmiHeader.biBitCount = 1; + else + bmiInfo->bmiHeader.biBitCount = 8; /* up to 256 colors */ + bmiInfo->bmiHeader.biCompression = BI_RGB; /* no compression */ + bmiInfo->bmiHeader.biSizeImage = 0; + bmiInfo->bmiHeader.biXPelsPerMeter = 0; + bmiInfo->bmiHeader.biYPelsPerMeter = 0; + bmiInfo->bmiHeader.biClrUsed = bm->colorcnt; /* number of colors used */ + bmiInfo->bmiHeader.biClrImportant = bm->colorcnt; + + /* + * create a transparency mask and paint to screen + */ + if( bm->type == mswIcon_bitmap ) { + memset( &bmiInfo->bmiColors[ 0 ], 0xFF, sizeof( RGBQUAD )); + memset( &bmiInfo->bmiColors[ 1 ], 0, sizeof( RGBQUAD )); + } else { + 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); + + /* now paint the bitmap with transparent set to black */ + if( bm->type == mswIcon_bitmap ) { + if( disabled ) { + col = color2; + } else { + col = color1; + } + memset( &bmiInfo->bmiColors[ 0 ], 0, sizeof( RGBQUAD )); + bmiInfo->bmiColors[ 1 ].rgbRed = GetRValue( col ); + bmiInfo->bmiColors[ 1 ].rgbGreen = GetGValue( col ); + bmiInfo->bmiColors[ 1 ].rgbBlue = GetBValue( col ); + } else { + if( disabled ) { + /* create a gray scale palette */ + for( i = 0; i < bm->colorcnt; i ++ ) { + byt = ( 30 * bm->colormap[ i ].rgbRed + + 59 * bm->colormap[ i ].rgbGreen + + 11 * bm->colormap[ i ].rgbBlue )/100; + + /* if totally black, use a dark gray */ + if( byt == 0 ) + byt = 0x66; + + bmiInfo->bmiColors[ i ].rgbRed = byt; + bmiInfo->bmiColors[ i ].rgbGreen = byt; + bmiInfo->bmiColors[ i ].rgbBlue = byt; + } + } else { + /* copy the palette */ + memcpy( (void *)bmiInfo->bmiColors, (void *)bm->colormap, bm->colorcnt * sizeof( RGBQUAD )); + } + 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); + + /* forget the data */ + free( bmiInfo ); +} + +/** + * Create a two color bitmap. This creates a two color icon. Pixels set to 1 are painted + * in the specified color, pixels set to 0 are transparent + * in order to convert the format, a lot of bit fiddling is necessary. The order of + * scanlines needs to be reversed and the bit order (high order - low order) is reversed + * as well. + * \param w IN width in pixels + * \param h IN height in pixels + * \param bits IN pixel data + * \param color IN color for foreground + * \return pointer to icon + */ + +wIcon_p wIconCreateBitMap( wPos_t w, wPos_t h, const char * bits, wDrawColor color ) +{ + int lineLength; + int i, j; + unsigned char *dest; + static unsigned char revbits[] = { 0, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E, 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F }; + unsigned long col = wDrawGetRGB( color ); + + wIcon_p ip; + ip = (wIcon_p)malloc( sizeof *ip ); + if( !ip ) { + fprintf( stderr, "Couldn't allocate memory for bitmap header.\n" ); + abort(); + } + + memset( ip, 0, sizeof *ip ); + ip->type = mswIcon_bitmap; + ip->w = w; + ip->h = h; + ip->colorcnt = 2; + + /* set up our two color palette */ + ip->colormap = malloc( 2 * sizeof( RGBQUAD )); + + ip->colormap[ 1 ].rgbBlue = col & 0xFF; + ip->colormap[ 1 ].rgbRed = (col>>16) & 0xFF; + ip->colormap[ 1 ].rgbGreen = (col>>8) & 0xFF; + ip->colormap[ 1 ].rgbReserved = 0; + + color = GetSysColor( COLOR_BTNFACE ); + ip->colormap[ 0 ].rgbBlue = GetBValue( color ); + ip->colormap[ 0 ].rgbRed = GetRValue( color ); + ip->colormap[ 0 ].rgbGreen = GetGValue( color ); + ip->colormap[ 0 ].rgbReserved = 0; + + lineLength = (((( ip->w + 7 ) / 8 ) + 3 ) >> 2 ) << 2; + ip->pixels = malloc( lineLength * ip->h ); + if( !ip->pixels ) { + fprintf( stderr, "Couldn't allocate memory for pixel data.\n" ); + abort(); + } + + /* + * copy the bits from source to the buffer, at this time the order of + * scanlines is reversed by starting with the last source line. + */ + for( i = 0; i < ip->h; i++ ) { + dest = ip->pixels + i * lineLength; + memcpy( dest, bits + ( ip->h - i - 1 ) * (( ip->w + 7) / 8), ( ip->w + 7 ) / 8 ); + + /* + * and now, the bit order is changed, this is done via a lookup table + */ + for( j = 0; j < lineLength; j++ ) + { + unsigned byte = dest[ j ]; + unsigned low = byte & 0x0F; + unsigned high = (byte & 0xF0) >> 4; + dest[ j ] = revbits[ low ]<<4 | revbits[ high ]; + } + } + + return ip; +} + +/** + * Create a pixmap. This functions interprets a XPM icon contained in a + * char array. Supported format are one or two byte per pixel and #rrggbb + * or #rrrrggggbbbb color specification. Color 'None' is interpreted as + * transparency, other symbolic names are not supported. + * + * \param pm IN XPM variable + * \return pointer to icon, call free() if not needed anymore. + */ + +wIcon_p wIconCreatePixMap( char *pm[]) +{ + wIcon_p ip; + int col, r, g, b, len; + int width, height; + char buff[3]; + char * cp, * cq, * ptr; + int i, j, k; + int lineLength; + unsigned *keys; + unsigned numchars; + unsigned pixel; + + ip = (wIcon_p)malloc( sizeof *ip ); + if( !ip ) { + fprintf( stderr, "Couldn't allocate memory for bitmap header.\n" ); + abort(); + } + + memset( ip, 0, sizeof *ip ); + ip->type = mswIcon_pixmap; + + /* extract values */ + cp = pm[0]; + width = (int)strtol(cp, &cq, 10 ); /* width of image */ + height = (int)strtol(cq, &cq, 10 ); /* height of image */ + col = (int)strtol(cq, &cq, 10 ); /* number of colors used */ + numchars = (int)strtol(cq, &cq, 10 ); /* get number of chars per pixel */ + + ip->colormap = malloc( col * sizeof( RGBQUAD )); + ip->w = width; + ip->h = height; + ip->colorcnt = col; /* number of colors used */ + + keys = malloc( sizeof( unsigned ) * col ); + + for ( col=0; col<(int)ip->colorcnt; col++ ) { + ptr = strdup( pm[col+1] ); /* create duplicate for input string*/ + + if( numchars == 1 ) { + keys[ col ] = (unsigned)ptr[0]; + } + else if( numchars == 2 ) { + keys[ col ] = (unsigned) ( ptr[ 0 ] + ptr[ 1 ] * 256 ); + } + + cp = strtok( ptr + numchars, "\t " ); /* cp points to color type */ + assert( *cp == 'c' ); /* should always be color */ + + cp = strtok( NULL, "\t " ); /* go to next token, the color definition itself */ + + if( *cp == '#' ) { /* is this a hex RGB specification? */ + len = strlen( cp+1 ) / 3; + assert( len == 4 || len == 2 ); /* expecting three 2 char or 4 char values */ + buff[2] = 0; /* if yes, extract the values */ + memcpy( buff, cp + 1, 2 ); + r = (int)strtol(buff, &cq, 16); + memcpy( buff, cp + 1 + len, 2 ); + g = (int)strtol(buff, &cq, 16); + memcpy( buff, cp + 1 + 2 * len, 2 ); + b = (int)strtol(buff, &cq, 16); + + ip->colormap[ col ].rgbBlue = b; + ip->colormap[ col ].rgbGreen = g; + ip->colormap[ col ].rgbRed = r; + ip->colormap[ col ].rgbReserved = 0; + + } else { + if( !stricmp( cp, "none" )) { /* special case transparency*/ + ip->transparent = col; + } + else + assert( *cp == '#' ); /* if no, abort for the moment */ + } + free( ptr ); + } + + /* get memory for the pixel data */ + /* dword align begin of line */ + lineLength = ((ip->w + 3 ) >> 2 ) << 2; + ip->pixels = malloc( lineLength * ip->h ); + if( !ip->pixels ) { + fprintf( stderr, "Couldn't allocate memory for pixel data.\n" ); + abort(); + } + + /* + convert the XPM pixel data to indexes into color table + at the same time the order of rows is reversed + Win32 should be able to do that but I couldn't find out + how, so this is coded by hand. + */ + + /* for all rows */ + for( i = 0; i < ip->h; i++ ) { + + cq = ip->pixels + lineLength * i; + /* get the next row */ + cp = pm[ ip->h - i + ip->colorcnt ]; + /* for all pixels in row */ + for( j = 0; j < ip->w; j++ ) { + /* get the pixel info */ + if( numchars == 1 ) + pixel = ( unsigned )*cp; + else + pixel = (unsigned) (*cp + *(cp+1)*256); + cp += numchars; + + /* look up pixel info in color table */ + k = 0; + while( pixel != keys[ k ] ) + k++; + + /* save the index into color table */ + *(cq + j) = k; + } + } + free( keys ); + + return ip; +} + +void wIconSetColor( wIcon_p ip, wDrawColor color ) +{ + unsigned long col = wDrawGetRGB( color ); + + if( ip->type == mswIcon_bitmap ) { + ip->colormap[ 1 ].rgbBlue = col & 0xFF; + ip->colormap[ 1 ].rgbRed = (col>>16) & 0xFF; + ip->colormap[ 1 ].rgbGreen = (col>>8) & 0xFF; + } +} + +/** + * Draw icon to screen. + * + * \param d IN drawing area + * \param bm IN bitmap to draw + * \param x IN x position + * \param y IN y position + */ + +void +wIconDraw( wDraw_p d, wIcon_p bm, wPos_t x, wPos_t y ) +{ + mswDrawIcon( d->hDc, (int)x, (int)y, bm, FALSE, 0, 0 ); +} + +/** + * Create a static control for displaying a bitmap. + * + * \param parent IN parent window + * \param x, y IN position in parent window + * \param option IN ignored for now + * \param iconP IN icon to use + * \return the control + */ + +wControl_p +wBitmapCreate( wWin_p parent, wPos_t x, wPos_t y, long option, wIcon_p iconP ) +{ + wBitmap_p control; + int index; + DWORD style = SS_OWNERDRAW | WS_VISIBLE | WS_CHILD; + + control = mswAlloc( parent, B_BITMAP, NULL, sizeof( struct wBitmap_t ), NULL, &index ); + mswComputePos( (wControl_p)control, x, y ); + control->option = option; + + control->hWnd = CreateWindow( "STATIC", NULL, + style, control->x, control->y, + iconP->w, iconP->h, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + + if (control->hWnd == NULL) { + mswFail("CreateWindow(BITMAP)"); + return (wControl_p)control; + } + control->h = iconP->h; + control->w = iconP->w; + control->data = iconP; + + return (wControl_p)control; +}
\ No newline at end of file diff --git a/app/wlib/mswlib/mswbox.c b/app/wlib/mswlib/mswbox.c new file mode 100644 index 0000000..04b3656 --- /dev/null +++ b/app/wlib/mswlib/mswbox.c @@ -0,0 +1,119 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Boxes + * + ***************************************************************************** + */ + +struct wBox_t { + WOBJ_COMMON + wBoxType_e boxTyp; + }; + +#define B (1) +#define W (2) +#define SETCOLOR( S, N ) \ + if ( lastColor != colors[bb->boxTyp][S][N] ) { \ + lastColor = colors[bb->boxTyp][S][N]; \ + SetROP2( hDc, (lastColor==B?R2_BLACK:R2_WHITE) ); \ + } + + +void wBoxSetSize( + wBox_p bb, + wPos_t w, + wPos_t h ) +{ + bb->w = w; + bb->h = h; +} + + +static void repaintBox( HWND hWnd, wControl_p b ) +{ + HDC hDc; + wBox_p bb = (wBox_p)(b); + wPos_t x0, y0, x1, y1; + char lastColor; + int lastRop; + static char colors[8][4][2] = { + { /* ThinB */ {B,0}, {B,0}, {B,0}, {B,0} }, + { /* ThinW */ {W,0}, {W,0}, {W,0}, {W,0} }, + { /* AboveW */ {W,0}, {W,0}, {B,0}, {B,0} }, + { /* BelowW */ {B,0}, {B,0}, {W,0}, {W,0} }, + { /* ThickB */ {B,B}, {B,B}, {B,B}, {B,B} }, + { /* ThickW */ {W,W}, {W,W}, {W,W}, {W,W} }, + { /* RidgeW */ {W,B}, {W,B}, {B,W}, {B,W} }, + { /* TroughW*/ {B,W}, {B,W}, {W,B}, {W,B} } }; + + x0 = bb->x; + x1 = bb->x+bb->w; + y0 = bb->y; + y1 = bb->y+bb->h; + hDc = GetDC( hWnd ); + MoveTo( hDc, x0, y1 ); + /*SETCOLOR( 0, 0 );*/ + lastColor = colors[bb->boxTyp][0][0]; + lastRop = SetROP2( hDc, (lastColor==B?R2_BLACK:R2_WHITE) ); + LineTo( hDc, x0, y0 ); + SETCOLOR( 1, 0 ); + LineTo( hDc, x1, y0 ); + SETCOLOR( 2, 0 ); + LineTo( hDc, x1, y1 ); + SETCOLOR( 3, 0 ); + LineTo( hDc, x0, y1 ); + if (bb->boxTyp >= wBoxThickB) { + x0++; y0++; x1--; y1--; + MoveTo( hDc, x0, y1 ); + SETCOLOR( 0, 1 ); + LineTo( hDc, x0, y0 ); + SETCOLOR( 1, 1 ); + LineTo( hDc, x1, y0 ); + SETCOLOR( 2, 1 ); + LineTo( hDc, x1, y1 ); + SETCOLOR( 3, 1 ); + LineTo( hDc, x0, y1 ); + } + SetROP2( hDc, lastRop ); + ReleaseDC( hWnd, hDc ); +} + + +static callBacks_t boxCallBacks = { + repaintBox, + NULL, + NULL }; + +wBox_p wBoxCreate( + wWin_p parent, + wPos_t origX, + wPos_t origY, + const char * labelStr, + wBoxType_e typ, + wPos_t width, + wPos_t height ) +{ + wBox_p b; + int index; + + b = (wBox_p)mswAlloc( parent, B_BOX, labelStr, sizeof *b, NULL, &index ); + b->boxTyp = typ; + + b->x = origX; + b->y = origY; + b->w = width; + b->h = height; + mswAddButton( (wControl_p)b, FALSE, NULL ); + mswCallBacks[B_BOX] = &boxCallBacks; + repaintBox( ((wControl_p)parent)->hWnd, (wControl_p)b ); + return b; +} diff --git a/app/wlib/mswlib/mswbutt.c b/app/wlib/mswlib/mswbutt.c new file mode 100644 index 0000000..b5d7b49 --- /dev/null +++ b/app/wlib/mswlib/mswbutt.c @@ -0,0 +1,387 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" +int kludge12 = 0; + +/* + ***************************************************************************** + * + * Simple Buttons + * + ***************************************************************************** + */ + + + +static XWNDPROC oldButtProc = NULL; +static XWNDPROC newButtProc; + + +struct wButton_t { + WOBJ_COMMON + wButtonCallBack_p action; + wBool_t busy; + wBool_t selected; + wIcon_p icon; + }; + + + +void mswButtPush( + wControl_p b ) +{ + if ( ((wButton_p)b)->action ) + ((wButton_p)b)->action( ((wButton_p)b)->data ); +} + +/** + * Paint function for toolbar buttons + * + * \param hButtDc IN valid device context + * \param bm IN bitmap to add to button + * \param selected IN selected state of button + * \param disabled IN disabled state of button + */ + +static void drawButton( + HDC hButtDc, + wIcon_p bm, + BOOL_T selected, + BOOL_T disabled ) +{ + HGDIOBJ oldBrush, newBrush; + HPEN oldPen, newPen; + RECT rect; + COLORREF color1, color2; + POS_T offw=5, offh=5; + TRIVERTEX vert[2] ; + GRADIENT_RECT gRect; + + COLORREF colL; + COLORREF colD; + COLORREF colF; + +#define LEFT (0) +#define RIGHT (bm->w+10) +#define TOP (0) +#define BOTTOM (bm->h+10) + + /* get the lightest and the darkest color to use */ + colL = GetSysColor( COLOR_BTNHIGHLIGHT ); + colD = GetSysColor( COLOR_BTNSHADOW ); + colF = GetSysColor( COLOR_BTNFACE ); + + /* define the rectangle for the button */ + rect.top = TOP; + rect.left = LEFT; + rect.right = RIGHT; + rect.bottom = BOTTOM; + + /* fill the button with the face color */ + newBrush = CreateSolidBrush( colF ); + oldBrush = SelectObject( hButtDc, newBrush ); + FillRect( hButtDc, &rect, newBrush ); + DeleteObject( SelectObject( hButtDc, oldBrush ) ); + + /* disabled button remain flat */ + if( !disabled ) + { + /* select colors for the gradient */ + if( selected ) { + color1 = colD; + color2 = colL; + } else { + color1 = colL; + color2 = colD; + } + +#define GRADIENT_WIDTH 6 + + /* + first draw the top gradient + this always ends in the button face color + starting color depends on button state (selected or not) + */ + vert [0] .x = LEFT; + vert [0] .y = TOP; + vert [0] .Red = GetRValue( color1 )* 256; + vert [0] .Green = GetGValue( color1 )* 256; + vert [0] .Blue = GetBValue( color1 )* 256; + vert [0] .Alpha = 0x0000; + vert [1] .x = RIGHT; + vert [1] .y = TOP + GRADIENT_WIDTH; + vert [1] .Red = GetRValue( colF )* 256; + vert [1] .Green = GetGValue( colF )* 256; + vert [1] .Blue = GetBValue( colF )* 256; + vert [1] .Alpha = 0x0000; + + gRect.UpperLeft = 0; + gRect.LowerRight = 1; + + GradientFill(hButtDc, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_V); + + /* + now draw the bottom gradient + this always starts with the button face color + ending color depends on button state (selected or not) + */ + vert [0] .x = LEFT; + vert [0] .y = BOTTOM - GRADIENT_WIDTH; + vert [0] .Red = GetRValue( colF )* 256; + vert [0] .Green = GetGValue( colF )* 256; + vert [0] .Blue = GetBValue( colF )* 256; + vert [0] .Alpha = 0x0000; + vert [1] .x = RIGHT; + vert [1] .y = BOTTOM; + vert [1] .Red = GetRValue( color2 )* 256; + vert [1] .Green = GetGValue( color2 )* 256; + vert [1] .Blue = GetBValue( color2 )* 256; + vert [1] .Alpha = 0x0000; + gRect.UpperLeft = 0; + gRect.LowerRight = 1; + GradientFill(hButtDc, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_V); + + } + + /* draw delimiting lines in shadow color */ + newPen = CreatePen( PS_SOLID, 0, colD ); + oldPen = SelectObject( hButtDc, newPen ); + + MoveTo( hButtDc, LEFT, TOP ); + LineTo( hButtDc, LEFT, BOTTOM ); + MoveTo( hButtDc, RIGHT, TOP ); + LineTo( hButtDc, RIGHT, BOTTOM ); + + DeleteObject( SelectObject( hButtDc, oldPen ) ); + + color2 = GetSysColor( COLOR_BTNSHADOW ); + color1 = RGB( bm->colormap[ 1 ].rgbRed, bm->colormap[ 1 ].rgbGreen, bm->colormap[ 1 ].rgbBlue ); + + if (selected) { + offw++; offh++; + } + mswDrawIcon( hButtDc, offw, offh, bm, disabled, color1, color2 ); +} + + +static void buttDrawIcon( + wButton_p b, + HDC butt_hDc ) +{ + wIcon_p bm = b->icon; + POS_T offw=5, offh=5; + + if (b->selected || b->busy) { + offw++; offh++; + } else if ( (b->option & BO_DISABLED) != 0 ) { + ; + } else { + ; + } + drawButton( butt_hDc, bm, b->selected || b->busy, (b->option & BO_DISABLED) != 0 ); +} + +void wButtonSetBusy( + wButton_p b, + int value ) +{ + b->busy = value; + if (!value) + b->selected = FALSE; + /*SendMessage( b->hWnd, BM_SETSTATE, (WPARAM)value, 0L );*/ + InvalidateRgn( b->hWnd, NULL, FALSE ); +} + + +void wButtonSetLabel( + wButton_p b, + const char * label ) +{ + if ((b->option&BO_ICON) == 0) { + /*b->labelStr = label;*/ + SetWindowText( b->hWnd, label ); + } else { + b->icon = (wIcon_p)label; + } + InvalidateRgn( b->hWnd, NULL, FALSE ); +} + + +static LRESULT buttPush( wControl_p b, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + wButton_p bb = (wButton_p)b; + DRAWITEMSTRUCT * di = (DRAWITEMSTRUCT *)lParam; + wBool_t selected; + + switch (message) { + case WM_COMMAND: + if (bb->action /*&& !bb->busy*/) { + bb->action( bb->data ); + return 0L; + } + break; + + case WM_MEASUREITEM: { + MEASUREITEMSTRUCT * mi = (MEASUREITEMSTRUCT *)lParam; + if (bb->type != B_BUTTON || (bb->option & BO_ICON) == 0) + break; + mi->CtlType = ODT_BUTTON; + mi->CtlID = wParam; + mi->itemWidth = bb->w; + mi->itemHeight = bb->h; + } return 0L; + + case WM_DRAWITEM: + if (bb->type == B_BUTTON && (bb->option & BO_ICON) != 0) { + selected = ((di->itemState & ODS_SELECTED) != 0); + if (bb->selected != selected) { + bb->selected = selected; + InvalidateRgn( bb->hWnd, NULL, FALSE ); + } + return TRUE; + } + break; + + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static void buttDone( + wControl_p b ) +{ + free(b); +} + +long FAR PASCAL _export pushButt( + HWND hWnd, + UINT message, + 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 + wButton_p b = (wButton_p)mswMapIndex( inx ); + PAINTSTRUCT ps; + + switch (message) { + case WM_PAINT: + if ( b && b->type == B_BUTTON && (b->option & BO_ICON) != 0 ) { + BeginPaint( hWnd, &ps ); + buttDrawIcon( (wButton_p)b, ps.hdc ); + EndPaint( hWnd, &ps ); + return 1L; + } + break; + 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_KILLFOCUS: + if ( b ) + InvalidateRect( b->hWnd, NULL, TRUE ); + return 0L; + break; + case WM_ERASEBKGND: + if (kludge12) + return 1L; + } + return CallWindowProc( oldButtProc, hWnd, message, wParam, lParam ); +} + +static callBacks_t buttonCallBacks = { + mswRepaintLabel, + buttDone, + buttPush }; + +wButton_p wButtonCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + wPos_t width, + wButtonCallBack_p action, + void * data ) +{ + wButton_p b; + RECT rect; + int h=20; + int index; + DWORD style; + HDC hDc; + wIcon_p bm; + + if (width <= 0) + width = 80; + if ((option&BO_ICON) == 0) { + labelStr = mswStrdup( labelStr ); + } else { + bm = (wIcon_p)labelStr; + labelStr = NULL; + } + b = (wButton_p)mswAlloc( parent, B_BUTTON, NULL, sizeof *b, data, &index ); + b->option = option; + b->busy = 0; + b->selected = 0; + mswComputePos( (wControl_p)b, x, y ); + if (b->option&BO_ICON) { + width = bm->w+10; + h = bm->h+10; + b->icon = bm; + } else { + width = (wPos_t)(width*mswScale); + } + style = ((b->option&BO_ICON)? BS_OWNERDRAW : BS_PUSHBUTTON) | + WS_CHILD | WS_VISIBLE | + mswGetBaseStyle(parent); + if ((b->option&BB_DEFAULT) != 0) + style |= BS_DEFPUSHBUTTON; + b->hWnd = CreateWindow( "BUTTON", labelStr, style, b->x, b->y, + /*CW_USEDEFAULT, CW_USEDEFAULT,*/ width, h, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(BUTTON)"); + return b; + } + /*SetWindowLong( b->hWnd, 0, (long)b );*/ + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + mswAddButton( (wControl_p)b, TRUE, helpStr ); + b->action = action; + mswCallBacks[B_BUTTON] = &buttonCallBacks; + mswChainFocus( (wControl_p)b ); + newButtProc = MakeProcInstance( (XWNDPROC)pushButt, mswHInst ); + oldButtProc = (XWNDPROC)GetWindowLong( b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newButtProc ); + if (mswPalette) { + hDc = GetDC( b->hWnd ); + SelectPalette( hDc, mswPalette, 0 ); + RealizePalette( hDc ); + ReleaseDC( b->hWnd, hDc ); + } + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + return b; +} diff --git a/app/wlib/mswlib/mswchksm.c b/app/wlib/mswlib/mswchksm.c new file mode 100644 index 0000000..602c204 --- /dev/null +++ b/app/wlib/mswlib/mswchksm.c @@ -0,0 +1,125 @@ +#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/mswchoic.c b/app/wlib/mswlib/mswchoic.c new file mode 100644 index 0000000..2ac391a --- /dev/null +++ b/app/wlib/mswlib/mswchoic.c @@ -0,0 +1,423 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "i18n.h" +#include "mswint.h" + +/* + ***************************************************************************** + * + * Choice Boxes + * + ***************************************************************************** + */ + +int CHOICE_HEIGHT=(17); +int CHOICE_MIN_WIDTH=25; + +static XWNDPROC oldChoiceItemProc = NULL; +static XWNDPROC newChoiceItemProc; + +typedef struct { + WOBJ_COMMON + wChoice_p owner; + } wChoiceItem_t, * wChoiceItem_p; + +struct wChoice_t { + WOBJ_COMMON + const char * * labels; + wChoiceItem_p *buttList; + long *valueP; + long oldVal; + wChoiceCallBack_p action; + HWND hBorder; + }; + +static FARPROC oldChoiceProc; + +void wRadioSetValue( + wChoice_p bc, + long val ) +{ + const char ** labels; + long cnt; + wChoiceItem_p * butts; + + butts = (wChoiceItem_p*)bc->buttList; + for (labels = bc->labels, cnt=0; *labels; labels++, cnt++, butts++ ) + SendMessage( (*butts)->hWnd, BM_SETCHECK, + (val==cnt)?1:0, 0L ); + bc->oldVal = val; + if (bc->valueP) + *bc->valueP = val; +} + +long wRadioGetValue( + wChoice_p bc ) +{ + return bc->oldVal; +} + + + +void wToggleSetValue( + wChoice_p bc, + long val ) +{ + const char ** labels; + long cnt; + wChoiceItem_p * butts; + + butts = (wChoiceItem_p*)bc->buttList; + for (labels = bc->labels, cnt=0; *labels; labels++, cnt++, butts++ ) + SendMessage( (*butts)->hWnd, BM_SETCHECK, + (val & (1L<<cnt)) != 0, 0L ); + bc->oldVal = val; + if (bc->valueP) + *bc->valueP = val; +} + + +long wToggleGetValue( + wChoice_p bc ) +{ + return bc->oldVal; +} + + +static void choiceSetBusy( + wControl_p b, + BOOL_T busy) +{ + wChoiceItem_p * butts; + wChoice_p bc = (wChoice_p)b; + + for (butts = (wChoiceItem_p*)bc->buttList; *butts; butts++ ) + EnableWindow( (*butts)->hWnd, !(BOOL)busy ); +} + +static void choiceShow( + wControl_p b, + BOOL_T show) +{ + wChoice_p bc = (wChoice_p)b; + wChoiceItem_p * butts; + + if ((bc->option & BC_NOBORDER)==0) + ShowWindow( bc->hBorder, show?SW_SHOW:SW_HIDE ); + + for (butts = (wChoiceItem_p*)bc->buttList; *butts; butts++ ) + ShowWindow( (*butts)->hWnd, show?SW_SHOW:SW_HIDE ); +} + +static void choiceSetPos( + wControl_p b, + wPos_t x, + wPos_t y ) +{ + wChoice_p bc = (wChoice_p)b; + wChoiceItem_p * butts; + wPos_t dx, dy; + + dx = x - bc->x; + dy = y - bc->y; + if ((bc->option & BC_NOBORDER)==0) + SetWindowPos( bc->hBorder, HWND_TOP, x, y, CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER ); + + for (butts = (wChoiceItem_p*)bc->buttList; *butts; butts++ ) { + SetWindowPos( (*butts)->hWnd, HWND_TOP, + (*butts)->x+=dx, (*butts)->y+=dy, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER ); + } + bc->x = x; + bc->y = y; +} + +long FAR PASCAL _export pushChoiceItem( + HWND hWnd, + UINT message, + 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 ); + + 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; + } + return CallWindowProc( oldChoiceItemProc, hWnd, message, wParam, lParam ); +} + +LRESULT choiceItemProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wChoiceItem_p me = (wChoiceItem_p)b, *rest; + wChoice_p bc; + int num; + + switch( message ) { + + case WM_COMMAND: + switch (WCMD_PARAM_NOTF) { + case BN_CLICKED: + bc = me->owner; + num = -1; + for (rest = (wChoiceItem_p*)bc->buttList; *rest; rest++ ) { + switch (bc->type) { + case B_TOGGLE: + num = rest-(wChoiceItem_p*)bc->buttList; + if (*rest == me) { + bc->oldVal ^= (1L<<num); + } + SendMessage( (*rest)->hWnd, BM_SETCHECK, + (bc->oldVal & (1L<<num)) != 0, 0L ); + break; + + case B_RADIO: + if (*rest != me) { + SendMessage( (*rest)->hWnd, BM_SETCHECK, 0, 0L ); + } else { + bc->oldVal = rest-(wChoiceItem_p*)bc->buttList; + SendMessage( (*rest)->hWnd, BM_SETCHECK, 1, 0L ); + } + break; + } + } + if (bc->valueP) + *bc->valueP = bc->oldVal; + if (bc->action) + bc->action( bc->oldVal, bc->data ); + break; + + } + break; + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static callBacks_t choiceCallBacks = { + mswRepaintLabel, + NULL, + NULL, + choiceSetBusy, + choiceShow, + choiceSetPos }; + +static callBacks_t choiceItemCallBacks = { + NULL, + NULL, + choiceItemProc }; + +/** + * Creates choice buttons. This function is used to create a group of + * radio buttons and checkboxes. + * + * \param type IN type of button + * \param parent IN parent window + * \param x, y IN position of group + * \param helpStr IN index string to find help + * \param labelStr IN label for group + * \param option IN ? + * \param labels IN labels for individual choices + * \param valueP OUT pointer for return value + * \param action IN ? + * \param data IN ? + * \return created choice button group + */ + +static wChoice_p choiceCreate( + wType_e type, + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + const char **labels, + long *valueP, + wChoiceCallBack_p action, + void *data ) +{ + wChoice_p b; + const char ** lp; + int cnt; + wChoiceItem_p * butts; + int ppx, ppy; + int bs; + HDC hDc; + HWND hButt; + int lab_l; + DWORD dw; + int w, maxW; + int pw, ph; + int index; + char * helpStrCopy; + HFONT hFont; + + b = mswAlloc( parent, type, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->valueP = valueP; + b->action = action; + b->labels = labels; + b->labelY += 6; + + ppx = b->x; + ppy = b->y; + + switch (b->type) { + case B_TOGGLE: + bs = BS_CHECKBOX; + break; + case B_RADIO: + bs = BS_RADIOBUTTON; + break; + } + for (lp = b->labels,cnt=0; *lp; lp++,cnt++ ); + butts = (wChoiceItem_p*)malloc( (cnt+1) * sizeof *butts ); + b->buttList = butts; + b->oldVal = (b->valueP?*b->valueP:0); + ph = pw = 2; + maxW = 0; + if (helpStr) + helpStrCopy = mswStrdup( helpStr ); + for (lp = b->labels, cnt=0; *lp; lp++, cnt++, butts++ ) { + *butts = (wChoiceItem_p)mswAlloc( parent, B_CHOICEITEM, + mswStrdup(_((char *)*lp)), sizeof( wChoiceItem_t ), data, &index ); + (*butts)->owner = b; + (*butts)->hWnd = hButt = CreateWindow( "BUTTON", (*butts)->labelStr, + bs | WS_CHILD | WS_VISIBLE | mswGetBaseStyle(parent), b->x+pw, b->y+ph, + 80, CHOICE_HEIGHT, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if ( hButt == (HWND)0 ) { + mswFail( "choiceCreate button" ); + return b; + } + (*butts)->x = b->x+pw; + (*butts)->y = b->y+ph; + if (b->hWnd == 0) + b->hWnd = (*butts)->hWnd; + (*butts)->helpStr = helpStrCopy; + + hDc = GetDC( hButt ); + lab_l = strlen((*butts)->labelStr); + + if (!mswThickFont) {hFont = SelectObject( hDc, mswLabelFont );} + dw = GetTextExtent( hDc, (char *)((*butts)->labelStr), lab_l ); + if (!mswThickFont) {SelectObject( hDc, hFont );} + + w = LOWORD(dw) + CHOICE_MIN_WIDTH; + + if (w > maxW) + maxW = w; + SetBkMode( hDc, TRANSPARENT ); + ReleaseDC( hButt, hDc ); + if (b->option & BC_HORZ) { + pw += w; + } else { + ph += CHOICE_HEIGHT; + } + if (!SetWindowPos( hButt, HWND_TOP, 0, 0, + w, CHOICE_HEIGHT, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("Create CHOICE: SetWindowPos"); + } + mswChainFocus( (wControl_p)*butts ); + newChoiceItemProc = MakeProcInstance( (XWNDPROC)pushChoiceItem, mswHInst ); + oldChoiceItemProc = (XWNDPROC)GetWindowLong( (*butts)->hWnd, GWL_WNDPROC ); + SetWindowLong( (*butts)->hWnd, GWL_WNDPROC, (LONG)newChoiceItemProc ); + if ( !mswThickFont ) + SendMessage( (*butts)->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + } + *butts = NULL; + switch (b->type) { + case B_TOGGLE: + wToggleSetValue( b, (b->valueP?*b->valueP:0L) ); + break; + case B_RADIO: + wRadioSetValue( b, (b->valueP?*b->valueP:0L) ); + break; + } + if (b->option & BC_HORZ) { + ph = CHOICE_HEIGHT; + } else { + pw = maxW; + } + pw += 4; ph += 4; + b->w = pw; + b->h = ph; + +#define FRAME_STYLE SS_ETCHEDFRAME + + if ((b->option & BC_NOBORDER)==0) { + b->hBorder = CreateWindow( "STATIC", NULL, WS_CHILD | WS_VISIBLE | FRAME_STYLE, + b->x, b->y, pw, ph, ((wControl_p)parent)->hWnd, 0, mswHInst, NULL ); + } + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[ B_CHOICEITEM ] = &choiceItemCallBacks; + mswCallBacks[ type ] = &choiceCallBacks; + return b; +} + + +wChoice_p wRadioCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + const char **labels, + long *valueP, + wChoiceCallBack_p action, + void *data ) +{ + return choiceCreate( B_RADIO, parent, x, y, helpStr, labelStr, + option, labels, valueP, action, data ); +} + +wChoice_p wToggleCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + const char **labels, + long *valueP, + wChoiceCallBack_p action, + void *data ) +{ + return choiceCreate( B_TOGGLE, parent, x, y, helpStr, labelStr, + option, labels, valueP, action, data ); +} diff --git a/app/wlib/mswlib/mswcolor.c b/app/wlib/mswlib/mswcolor.c new file mode 100644 index 0000000..41bf6a9 --- /dev/null +++ b/app/wlib/mswlib/mswcolor.c @@ -0,0 +1,362 @@ +/* + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswcolor.c,v 1.2 2007-01-14 08:43:32 m_fischer Exp $ + */ + +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <windows.h> + +#include "mswint.h" + +#include "square10.bmp" + +/* + ***************************************************************************** + * + * Color + * + ***************************************************************************** + */ + +#define NUM_GRAYS (16) +#define NUM_COLORS (256) + +wDrawColor wDrawColorWhite = 0; +wDrawColor wDrawColorBlack = 1; + +#define MAX_COLOR_DISTANCE (3) + +static void mswGetCustomColors( void ); + + +static struct { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[NUM_COLORS]; + } colorPalette = { + 0x300, + 2, + { + { 255, 255, 255 }, /* White */ + { 0, 0, 0 } /* Black */ + } }; + +COLORREF mappedColors[NUM_COLORS]; + + +static long flipRGB( long rgb ) +{ + rgb = ((rgb>>16)&0xFF) | (rgb&0x00FF00) | ((rgb&0xFF)<<16); + return rgb; +} + + +static void getpalette( void ) +{ + + HDC hdc; + int inx, cnt; + PALETTEENTRY pe[256]; + FILE * f; + hdc = GetDC(mswHWnd); + if (!(GetDeviceCaps( hdc, RASTERCAPS) & RC_PALETTE)) { + ReleaseDC( mswHWnd, hdc ); + return; + } + cnt = GetDeviceCaps(hdc, SIZEPALETTE); + GetSystemPaletteEntries( hdc, 0, cnt, pe ); + f = fopen( "palette.txt", "w" ); + for (inx=0;inx<cnt;inx++) + fprintf(f, "%d [ %d %d %d %d ]\n", inx, pe[inx].peRed, pe[inx].peGreen, pe[inx].peBlue, pe[inx].peFlags ); + fclose(f); + ReleaseDC( mswHWnd, hdc ); +} + + +static int findColor( int r0, int g0, int b0 ) +{ + int r1, g1, b1; + int d0, d1; + int c, cc; + PALETTEENTRY *pal; + + pal = colorPalette.palPalEntry; + cc = (int)wDrawColorBlack; + d0 = 256*3; + + for ( c = 0; c < (int)colorPalette.palNumEntries; c++ ) { + r1 = pal[c].peRed; + b1 = pal[c].peBlue; + g1 = pal[c].peGreen; + d1 = abs(r0-r1) + abs(g0-g1) + abs(b0-b1); + if (d1 == 0) + return c; + if (d1 < d0) { + d0 = d1; + cc = c; + } + } + if ( colorPalette.palNumEntries < 128 ) { + pal[colorPalette.palNumEntries].peRed = r0; + pal[colorPalette.palNumEntries].peGreen = g0; + pal[colorPalette.palNumEntries].peBlue = b0; + if ( mswPalette ) { + ResizePalette( mswPalette, colorPalette.palNumEntries+1 ); + SetPaletteEntries( mswPalette, colorPalette.palNumEntries, 1, &pal[colorPalette.palNumEntries] ); + } + return colorPalette.palNumEntries++; + } + return cc; +} + + +int mswGetPaletteClock( void ) +{ + return colorPalette.palNumEntries; +} + + +void mswInitColorPalette( void ) +{ + static int initted = FALSE; + HDC hDc; + int cnt; + int rc; + static struct { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[256]; + } pe; + + if (initted) + return; + + initted = TRUE; + mswGetCustomColors(); + mswFontInit(); + hDc = GetDC(mswHWnd); + if (!(GetDeviceCaps( hDc, RASTERCAPS) & RC_PALETTE)) { + ReleaseDC( mswHWnd, hDc ); + return; + } + cnt = GetDeviceCaps(hDc, SIZEPALETTE); + rc = GetSystemPaletteEntries( hDc, 0, cnt, pe.palPalEntry ); + mswPalette = CreatePalette( (const LOGPALETTE FAR*)&colorPalette ); + ReleaseDC( mswHWnd, hDc ); + +} + + +HPALETTE mswCreatePalette( void ) +{ + return CreatePalette( (const LOGPALETTE FAR*)&colorPalette ); +} + + +int mswGetColorList( RGBQUAD * colors ) +{ + int i; + for (i=0;i<(int)colorPalette.palNumEntries;i++) { + colors[i].rgbBlue = colorPalette.palPalEntry[i].peBlue; + colors[i].rgbGreen = colorPalette.palPalEntry[i].peGreen; + colors[i].rgbRed = colorPalette.palPalEntry[i].peRed; + colors[i].rgbReserved = 0; + } + return NUM_COLORS; +} + + +COLORREF mswGetColor( wBool_t hasPalette, wDrawColor color ) +{ + if ( hasPalette ) + return PALETTEINDEX(color); + else + return RGB( colorPalette.palPalEntry[color].peRed, colorPalette.palPalEntry[color].peGreen, colorPalette.palPalEntry[color].peBlue ); +} + + +wDrawColor wDrawColorGray( + int percent ) +{ + int n; + n = (percent * NUM_GRAYS) / 100; + if ( n <= 0 ) + return wDrawColorBlack; + else if ( n > NUM_GRAYS ) + return wDrawColorWhite; + else { + n = (n*256)/NUM_GRAYS; + return wDrawFindColor( wRGB(n,n,n) ); + } +} + +wDrawColor wDrawFindColor( + long rgb0 ) +{ + static long saved_rgb = wRGB(255,255,255); + static wDrawColor saved_color = 0; + int r0, g0, b0; + + if (rgb0 == saved_rgb) + return saved_color; + r0 = (int)(rgb0>>16)&0xFF; + g0 = (int)(rgb0>>8)&0xFF; + b0 = (int)(rgb0)&0xFF; + saved_rgb = rgb0; + return saved_color = findColor( r0, g0, b0 ); +} + + +long wDrawGetRGB( + wDrawColor color ) +{ + long rgb; + int r, g, b; + r = colorPalette.palPalEntry[color].peRed; + g = colorPalette.palPalEntry[color].peGreen; + b = colorPalette.palPalEntry[color].peBlue; + rgb = wRGB(r,g,b); + return rgb; +} + + +static CHOOSECOLOR chooseColor; +static COLORREF aclrCust[16]; + +static void mswGetCustomColors( void ) +{ + int inx; + char colorName[10]; + long rgb; + + strcpy( colorName, "custom-" ); + for ( inx=0; inx<16; inx++ ) { + sprintf( colorName+7, "%d", inx ); + wPrefGetInteger( "mswcolor", colorName, &rgb, 0 ); + aclrCust[inx] = flipRGB(rgb); + } +} + + +void mswPutCustomColors( void ) +{ + int inx; + char colorName[10]; + long rgb; + + strcpy( colorName, "custom-" ); + for ( inx=0; inx<16; inx++ ) { + rgb = flipRGB(aclrCust[inx]); + if ( rgb != 0 ) { + sprintf( colorName+7, "%d", inx ); + wPrefSetInteger( "mswcolor", colorName, rgb ); + } + } +} + + +wBool_t wColorSelect( + const char * title, + wDrawColor * color ) +{ + long rgb; + + memset( &chooseColor, 0, sizeof chooseColor ); + rgb = flipRGB(wDrawGetRGB(*color)); + chooseColor.lStructSize = sizeof chooseColor; + chooseColor.hwndOwner = mswHWnd; + chooseColor.hInstance = NULL; + chooseColor.rgbResult = rgb; + chooseColor.lpCustColors = aclrCust; + chooseColor.Flags = CC_RGBINIT; + chooseColor.lCustData = 0L; + chooseColor.lpfnHook = NULL; + chooseColor.lpTemplateName = (LPSTR)NULL; + if ( ChooseColor( &chooseColor ) ) { + rgb = flipRGB(chooseColor.rgbResult); + *color = wDrawFindColor(rgb); + return TRUE; + } + return FALSE; +} + + +typedef struct { + wDrawColor * valueP; + wColorSelectButtonCallBack_p action; + const char * labelStr; + void * data; + wDrawColor color; + wButton_p button; + wIcon_p bm; + } colorData_t; + + +static void doColorButton( + void * data ) +{ + colorData_t * cd = (colorData_t*)data; + wDrawColor newColor; + + newColor = cd->color; + if (wColorSelect( cd->labelStr, &newColor )) { + cd->color = newColor; + wColorSelectButtonSetColor( cd->button, newColor ); + if (cd->valueP) + *cd->valueP = newColor; + if (cd->action) + cd->action( cd->data, newColor ); + } +} + + +wButton_p wColorSelectButtonCreate( + wWin_p win, + wPos_t x, + wPos_t y, + const char * helpStr, + const char * labelStr, + long option, + wPos_t width, + wDrawColor * color, + wColorSelectButtonCallBack_p action, + void * data ) +{ + wButton_p bb; + wIcon_p bm; + colorData_t * cd; + bm = wIconCreateBitMap( square10_width, square10_height, square10_bits, (color?*color:0) ); + cd = malloc( sizeof *cd ); + cd->valueP = color; + cd->action = action; + cd->data = data; + cd->labelStr = labelStr; + cd->color = (color?*color:0); + cd->bm = bm; + bb = wButtonCreate( win, x, y, helpStr, (char*)bm, option|BO_ICON, width, doColorButton, cd ); + cd->button = bb; + if ( labelStr ) + wControlSetLabel( (wControl_p)bb, labelStr ); + return bb; +} + + +void wColorSelectButtonSetColor( + wButton_p bb, + wDrawColor color ) +{ + ((colorData_t*)((wControl_p)bb)->data)->color = color; + wIconSetColor( ((colorData_t*)((wControl_p)bb)->data)->bm, color ); + InvalidateRect( ((wControl_p)bb)->hWnd, NULL, TRUE ); +} + + +wDrawColor wColorSelectButtonGetColor( + wButton_p bb ) +{ + return ((colorData_t*)((wControl_p)bb)->data)->color; +} diff --git a/app/wlib/mswlib/mswdraw.c b/app/wlib/mswlib/mswdraw.c new file mode 100644 index 0000000..498b49e --- /dev/null +++ b/app/wlib/mswlib/mswdraw.c @@ -0,0 +1,1783 @@ +/* + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswdraw.c,v 1.6 2009-05-15 18:16:16 m_fischer Exp $ + */ + +#define _WIN32_WINNT 0x0500 /* for wheel mouse supposrt */ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <winuser.h> + +#ifdef WIN32 +#define wFont_t tagLOGFONTA +#else +#define wFont_t tagLOGFONT +#endif +#include "mswint.h" + +/* + ***************************************************************************** + * + * Draw + * + ***************************************************************************** + */ + +static wBool_t initted = FALSE; + +long wDebugFont; + +static FARPROC oldDrawProc; + + +static long tmpOp = 0x990066; +static long setOp = 0x8800c6; +static long clrOp = 0xbb0226; + +#define CENTERMARK_LENGTH 6 + +#ifdef SLOW +static wPos_t XPIX2INCH( wDraw_p d, int ix ) +{ + return (wPos_t)ix; +} + +static wPos_t YPIX2INCH( wDraw_p d, int iy ) +{ + wPos_t y; + y = (wPos_t)(d->h-2-iy); + return y; +} + +static int XINCH2PIX( wDraw_p d, wPos_t xx ) +{ + int ix; + ix = (int)(xx); + return ix; +} + +static int YINCH2PIX( wDraw_p d, wPos_t y ) +{ + int iy; + iy = d->h-2 - (int)(y); + return iy; +} + + +static wPos_t XPIXELSTOINCH( wDraw_p d, int ix ) +{ + return (wPos_t)ix; +} + + +static wPos_t YPIXELSTOINCH( wDraw_p d, int iy ) +{ + return (wPos_t)iy; +} +#else +#define XPIX2INCH( d, ix ) \ + ((wPos_t)ix) + +#define YPIX2INCH( d, iy ) \ + ((wPos_t)(d->h-2-iy)) + +#define XINCH2PIX( d, xx ) \ + ((int)(xx)) + +#define YINCH2PIX( d, y ) \ + (d->h-2 - (int)(y)) + + +#define XPIXELSTOINCH( d, ix ) \ + ((wPos_t)ix) + + +#define YPIXELSTOINCH( d, iy ) \ + ((wPos_t)iy) + +#endif + +/* + ***************************************************************************** + * + * Basic Line Draw + * + ***************************************************************************** + */ + + + +static long noNegDrawArgs = -1; +static long noFlatEndCaps = 0; + +void wDrawDelayUpdate( + wDraw_p d, + wBool_t delay ) +{ +} + +/** + * Sets the proper pen and composition for the next drawing operation + * + * + * \param hDc IN device context + * \param d IN ??? + * \param dw IN line width + * \param lt IN line type (dashed, solid, ...) + * \param dc IN color + * \param dopt IN ???? + */ + +static void setDrawMode( + HDC hDc, + wDraw_p d, + wDrawWidth dw, + wDrawLineType_e lt, + wDrawColor dc, + wDrawOpts dopt ) +{ + int mode; + HPEN hOldPen; + static wDraw_p d0; + static wDrawWidth dw0 = -1; + static wDrawLineType_e lt0 = (wDrawLineType_e)-1; + static wDrawColor dc0 = -1; + static int mode0 = -1; + static LOGBRUSH logBrush = { 0, 0, 0 }; + DWORD penStyle; + + if ( d->hasPalette ) { + int winPaletteClock = mswGetPaletteClock(); + if ( d->paletteClock < winPaletteClock ) { + RealizePalette( hDc ); + d->paletteClock = winPaletteClock; + } + } + + if (dopt & wDrawOptTemp) { + mode = R2_NOTXORPEN; + } else { + mode = R2_COPYPEN; + } + SetROP2( hDc, mode ); + if ( d == d0 && mode == mode0 && dw0 == dw && lt == lt0 && dc == dc0 ) + return; + + // make sure that the line width is at least 1! + if( !dw ) + dw++; + + d0 = d; mode0 = mode; dw0 = dw; lt0 = lt; dc0 = dc; + + logBrush.lbColor = mswGetColor(d->hasPalette,dc); + if ( lt==wDrawLineSolid ) { + penStyle = PS_GEOMETRIC | PS_SOLID; + if ( noFlatEndCaps == FALSE ) + penStyle |= PS_ENDCAP_FLAT; + d->hPen = ExtCreatePen( penStyle, + dw, + &logBrush, + 0, + NULL ); + /*colorPalette.palPalEntry[dc] );*/ + } else { + d->hPen = CreatePen( PS_DOT, 0, mswGetColor( d->hasPalette, dc ) ); + } + hOldPen = SelectObject( hDc, d->hPen ); + DeleteObject( hOldPen ); +} + +static void setDrawBrush( + HDC hDc, + wDraw_p d, + wDrawColor dc, + wDrawOpts dopt ) +{ + HBRUSH hOldBrush; + static wDraw_p d0; + static wDrawColor dc0 = -1; + + setDrawMode( hDc, d, 0, wDrawLineSolid, dc, dopt ); + if ( d == d0 && dc == dc0 ) + return; + + d0 = d; dc0 = dc; + + d->hBrush = CreateSolidBrush( + mswGetColor(d->hasPalette,dc) ); + hOldBrush = SelectObject( hDc, d->hBrush ); + DeleteObject( hOldBrush ); +} + + +static void myInvalidateRect( + wDraw_p d, + RECT * prect ) +{ + if ( prect->top < 0 ) prect->top = 0; + if ( prect->left < 0 ) prect->left = 0; + if ( prect->bottom > d->h ) prect->bottom = d->h; + if ( prect->right > d->w ) prect->right = d->w; + InvalidateRect( d->hWnd, prect, FALSE ); +} + + +static int clip0( POINT * p0, POINT * p1, wDraw_p d ) +{ + long int x0=p0->x, y0=p0->y, x1=p1->x, y1=p1->y; + long int dx, dy; + if ( x0<0 && x1<0 ) return 0; + if ( y0<0 && y1<0 ) return 0; + dx=x1-x0; + dy=y1-y0; + if ( x0 < 0 ) { + y0 -= x0*dy/dx; + x0 = 0; + } + if ( y0 < 0 ) { + if ( (x0 -= y0*dx/dy) < 0 ) return 0; + y0 = 0; + } + if ( x1 < 0 ) { + y1 -= x1*dy/dx; + x1 = 0; + } + if ( y1 < 0 ) { + if ( (x1 -= y1*dx/dy) < 0 ) return 0; + y1 = 0; + } + p0->x = (int)x0; + p0->y = (int)y0; + p1->x = (int)x1; + p1->y = (int)y1; + return 1; +} + + +void wDrawLine( + wDraw_p d, + wPos_t p0x, + wPos_t p0y, + wPos_t p1x, + wPos_t p1y, + wDrawWidth dw, + wDrawLineType_e lt, + wDrawColor dc, + wDrawOpts dopt ) +{ + POINT p0, p1; + RECT rect; + setDrawMode( d->hDc, d, dw, lt, dc, dopt ); + p0.x = XINCH2PIX(d,p0x); + p0.y = YINCH2PIX(d,p0y); + p1.x = XINCH2PIX(d,p1x); + p1.y = YINCH2PIX(d,p1y); + if ( noNegDrawArgs>0 && !clip0( &p0, &p1, d ) ) + return; + MoveTo( d->hDc, p0.x, p0.y ); + LineTo( d->hDc, p1.x, p1.y ); + if (d->hWnd) { + if (dw==0) + dw = 1; + dw++; + if (p0.y<p1.y) { + rect.top = p0.y-dw; + rect.bottom = p1.y+dw; + } else { + rect.top = p1.y-dw; + rect.bottom = p0.y+dw; + } + if (p0.x<p1.x) { + rect.left = p0.x-dw; + rect.right = p1.x+dw; + } else { + rect.left = p1.x-dw; + rect.right = p0.x+dw; + } + myInvalidateRect( d, &rect ); + } +} + +static double mswsin( double angle ) +{ + while (angle < 0.0) angle += 360.0; + while (angle >= 360.0) angle -= 360.0; + angle *= (M_PI*2.0)/360.0; + return sin( angle ); +} + +static double mswcos( double angle ) +{ + while (angle < 0.0) angle += 360.0; + while (angle >= 360.0) angle -= 360.0; + angle *= (M_PI*2.0)/360.0; + return cos( angle ); +} + +static double mswasin( double x, double h ) +{ + double angle; + angle = asin( x/h ); + angle /= (M_PI*2.0)/360.0; + return angle; +} + +/** + * Draw an arc around a specified center + * + * \param d IN ? + * \param px, py IN center of arc + * \param r IN radius + * \param a0, a1 IN start and end angle + * \param drawCenter draw marking for center + * \param dw line width + * \param lt line type + * \param dc color + * \param dopt ? + */ + + +void wDrawArc( + wDraw_p d, + wPos_t px, + wPos_t py, + wPos_t r, + double a0, + double a1, + int drawCenter, + wDrawWidth dw, + wDrawLineType_e lt, + wDrawColor dc, + wDrawOpts dopt ) +{ + int i, cnt; + POINT p0, p1, ps, pe, pp0, pp1, pp2, pc; + double psx, psy, pex, pey, len, aa; + RECT rect; + int needMoveTo; + wBool_t fakeArc = FALSE; + + len = a1/360.0 * (2 * M_PI) * r; + if (len < 3) + return; + + p0.x = XINCH2PIX(d,px-r); + p0.y = YINCH2PIX(d,py+r)+1; + p1.x = XINCH2PIX(d,px+r); + p1.y = YINCH2PIX(d,py-r)+1; + + pex = px + r * mswsin(a0); + pey = py + r * mswcos(a0); + psx = px + r * mswsin(a0+a1); + psy = py + r * mswcos(a0+a1); + + /*pointOnCircle( &pe, p, r, a0 ); + pointOnCircle( &ps, p, r, a0+a1 );*/ + ps.x = XINCH2PIX(d,(wPos_t)psx); + ps.y = YINCH2PIX(d,(wPos_t)psy); + pe.x = XINCH2PIX(d,(wPos_t)pex); + pe.y = YINCH2PIX(d,(wPos_t)pey); + + setDrawMode( d->hDc, d, dw, lt, dc, dopt ); + + if (dw == 0) + dw = 1; + + if (r>4096) { + /* The book says 32K but experience says otherwise */ + fakeArc = TRUE; + } + if ( noNegDrawArgs > 0 ) { + if ( p0.x < 0 || p0.y < 0 || p1.x < 0 || p1.y < 0 ) + fakeArc = TRUE; + } + if ( fakeArc ) { + cnt = (int)a1; + if ( cnt <= 0 ) cnt = 1; + if ( cnt > 360 ) cnt = 360; + aa = a1 / cnt; + psx = px + r * mswsin(a0); + psy = py + r * mswcos(a0); + pp0.x = XINCH2PIX( d, (wPos_t)psx ); + pp0.y = YINCH2PIX( d, (wPos_t)psy ); + needMoveTo = TRUE; + for ( i=0; i<cnt; i++ ) { + a0 += aa; + psx = px + r * mswsin(a0); + psy = py + r * mswcos(a0); + pp2.x = pp1.x = XINCH2PIX( d, (wPos_t)psx ); + pp2.y = pp1.y = YINCH2PIX( d, (wPos_t)psy ); + if ( clip0( &pp0, &pp1, d ) ) { + if (needMoveTo) { + MoveTo( d->hDc, pp0.x, pp0.y ); + needMoveTo = FALSE; + } + LineTo( d->hDc, pp1.x, pp1.y ); + } else { + needMoveTo = TRUE; + } + pp0.x = pp2.x; pp0.y = pp2.y; + } + } else { + if ( a0 == 0.0 && a1 == 360.0 ) { + Arc( d->hDc, p0.x, p1.y, p1.x, p0.y, ps.x, p0.y-1, pe.x, p1.y-1 ); + Arc( d->hDc, p0.x, p1.y, p1.x, p0.y, ps.x, p1.y-1, pe.x, p0.y-1 ); + } else { + Arc( d->hDc, p0.x, p1.y, p1.x, p0.y, ps.x, ps.y, pe.x, pe.y ); + } + } + + // should the center of the arc be drawn? + if( drawCenter ) { + + // calculate the center coordinates + pc.x = XINCH2PIX( d, px ); + pc.y = YINCH2PIX( d, py ); + // now draw the crosshair + MoveTo( d->hDc, pc.x - CENTERMARK_LENGTH/2, pc.y ); + LineTo( d->hDc, pc.x + CENTERMARK_LENGTH/2, pc.y ); + MoveTo( d->hDc, pc.x, pc.y - CENTERMARK_LENGTH/2 ); + LineTo( d->hDc, pc.x, pc.y + CENTERMARK_LENGTH/2 ); + + // invalidate the area of the crosshair + rect.top = pc.y - CENTERMARK_LENGTH / 2 - 1; + rect.bottom = pc.y + CENTERMARK_LENGTH / 2 + 1; + rect.left = pc.x - CENTERMARK_LENGTH / 2 - 1; + rect.right = pc.x + CENTERMARK_LENGTH / 2 + 1; + myInvalidateRect( d, &rect ); + } + + if (d->hWnd) { + dw++; + a1 += a0; + if (a1>360.0) + rect.top = p0.y; + else + rect.top = min(pe.y,ps.y); + if (a1>(a0>180?360.0:0.0)+180) + rect.bottom = p1.y; + else + rect.bottom = max(pe.y,ps.y); + if (a1>(a0>270?360.0:0.0)+270) + rect.left = p0.x; + else + rect.left = min(pe.x,ps.x); + if (a1>(a0>90?360.0:0.0)+90) + rect.right = p1.x; + else + rect.right = max(pe.x,ps.x); + rect.top -= dw; + rect.bottom += dw; + rect.left -= dw; + rect.right += dw; + myInvalidateRect( d, &rect ); + + } +} + +void wDrawPoint( + wDraw_p d, + wPos_t px, + wPos_t py, + wDrawColor dc, + wDrawOpts dopt ) +{ + POINT p0; + RECT rect; + + p0.x = XINCH2PIX(d,px); + p0.y = YINCH2PIX(d,py); + + if ( p0.x < 0 || p0.y < 0 ) + return; + if ( p0.x >= d->w || p0.y >= d->h ) + return; + setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt ); + + SetPixel( d->hDc, p0.x, p0.y, mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/ ); + if (d->hWnd) { + rect.top = p0.y-1; + rect.bottom = p0.y+1; + rect.left = p0.x-1; + rect.right = p0.x+1; + myInvalidateRect( d, &rect ); + } +} + +/* + ***************************************************************************** + * + * Fonts + * + ***************************************************************************** + */ + + +static LOGFONT logFont = { + /* Initial default values */ + -24, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" }; + +static LOGFONT timesFont[2][2] = { + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" } }, + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Times" } } }; + +static LOGFONT helvFont[2][2] = { + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" } }, + { { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Arial" }, + { + /* Initial default values */ + 0, 0, /* H, W */ + 0, /* A */ + 0, + FW_BOLD, + 1, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + 0, /* P&F */ + "Hevletica" } } }; + + +void mswFontInit( void ) +{ + const char * face; + long size; + face = wPrefGetString( "msw window font", "face" ); + wPrefGetInteger( "msw window font", "size", &size, -24 ); + if (face) { + strncpy( logFont.lfFaceName, face, LF_FACESIZE ); + } + logFont.lfHeight = (int)size; +} + + +static CHOOSEFONT chooseFont; +static wFontSize_t fontSize = 18; +static double fontFactor = 1.0; + +static void doChooseFont( void ) +{ + int rc; + memset( &chooseFont, 0, sizeof chooseFont ); + chooseFont.lStructSize = sizeof chooseFont; + chooseFont.hwndOwner = mswHWnd; + chooseFont.lpLogFont = &logFont; + chooseFont.Flags = CF_SCREENFONTS|CF_SCALABLEONLY|CF_INITTOLOGFONTSTRUCT; + chooseFont.nFontType = SCREEN_FONTTYPE; + rc = ChooseFont( &chooseFont ); + if (rc) { + fontSize = (wFontSize_t)(-logFont.lfHeight * 72) / 96.0 / fontFactor; + if (fontSize < 1) + fontSize = 1; + wPrefSetString( "msw window font", "face", logFont.lfFaceName ); + wPrefSetInteger( "msw window font", "size", logFont.lfHeight ); + } +} + +static int computeFontSize( wDraw_p d, double siz ) +{ + int ret; + siz = (siz * d->DPI) / 72.0; + ret = (int)(siz * fontFactor); + if (ret < 1) + ret = 1; + return -ret; +} + +void wDrawGetTextSize( + wPos_t *w, + wPos_t *h, + wPos_t *d, + wDraw_p bd, + const char * text, + wFont_p fp, + double siz ) +{ + int x, y; + HFONT newFont, prevFont; + DWORD extent; + int oldLfHeight; + if (fp == NULL) + fp = &logFont; + fp->lfEscapement = 0; + oldLfHeight = fp->lfHeight; + fp->lfHeight = computeFontSize( bd, siz ); + fp->lfWidth = 0; + newFont = CreateFontIndirect( fp ); + prevFont = SelectObject( bd->hDc, newFont ); + extent = GetTextExtent( bd->hDc, CAST_AWAY_CONST text, strlen(text) ); + x = LOWORD(extent); + y = HIWORD(extent); + *w = XPIXELSTOINCH( bd, x ); + *h = YPIXELSTOINCH( bd, y ); + *d = 0; + SelectObject( bd->hDc, prevFont ); + DeleteObject( newFont ); + fp->lfHeight = oldLfHeight; +} + +void wDrawString( + wDraw_p d, + wPos_t px, + wPos_t py, + double angle, + const char * text, + wFont_p fp, + double siz, + wDrawColor dc, + wDrawOpts dopts ) +{ + int x, y; + HFONT newFont, prevFont; + HDC newDc; + HBITMAP oldBm, newBm; + DWORD extent; + int w, h; + RECT rect; + int oldLfHeight; + + if (fp == NULL) + fp = &logFont; + oldLfHeight = fp->lfHeight; + fp->lfEscapement = (int)(angle*10.0); + fp->lfHeight = computeFontSize( d, siz ); + fp->lfWidth = 0; + newFont = CreateFontIndirect( fp ); + x = XINCH2PIX(d,px) + (int)(mswsin(angle)*fp->lfHeight-0.5); + y = YINCH2PIX(d,py) + (int)(mswcos(angle)*fp->lfHeight-0.5); + if ( noNegDrawArgs > 0 && ( x < 0 || y < 0 ) ) + return; + if (dopts & wDrawOptTemp) { + setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopts ); + newDc = CreateCompatibleDC( d->hDc ); + prevFont = SelectObject( newDc, newFont ); + extent = GetTextExtent( newDc, CAST_AWAY_CONST text, strlen(text) ); + w = LOWORD(extent); + h = HIWORD(extent); + if ( h > w ) w = h; + newBm = CreateCompatibleBitmap( d->hDc, w*2, w*2 ); + oldBm = SelectObject( newDc, newBm ); + rect.top = rect.left = 0; + rect.bottom = rect.right = w*2; + FillRect( newDc, &rect, GetStockObject(WHITE_BRUSH) ); + TextOut( newDc, w, w, text, strlen(text) ); + BitBlt( d->hDc, x-w, y-w, w*2, w*2, newDc, 0, 0, tmpOp ); + SelectObject( newDc, oldBm ); + DeleteObject( newBm ); + SelectObject( newDc, prevFont ); + DeleteDC( newDc ); + if (d->hWnd) { + rect.top = y-(w+1); + rect.bottom = y+(w+1); + rect.left = x-(w+1); + rect.right = x+(w+1); + myInvalidateRect( d, &rect ); + } +#ifdef LATER + /* KLUDGE: Can't Invert text, so we just draw a bow - a pox on windows*/ + MoveTo( d->hDc, x, y ); + LineTo( d->hDc, x+w, y ); + LineTo( d->hDc, x+w, y+h ); + LineTo( d->hDc, x, y+h ); + LineTo( d->hDc, x, y ); +#endif + } else { + prevFont = SelectObject( d->hDc, newFont ); + SetBkMode( d->hDc, TRANSPARENT ); + if (dc != wDrawColorBlack) { + COLORREF old; + old = SetTextColor( d->hDc, mswGetColor(d->hasPalette,dc)/*colorPalette.palPalEntry[dc]*/ ); + TextOut( d->hDc, x, y, text, strlen(text) ); + SetTextColor( d->hDc, old ); + } else + TextOut( d->hDc, x, y, text, strlen(text) ); + extent = GetTextExtent( d->hDc, CAST_AWAY_CONST text, strlen(text) ); + SelectObject( d->hDc, prevFont ); + w = LOWORD(extent); + h = HIWORD(extent); + if (d->hWnd) { + rect.top = y-(w+h+1); + rect.bottom = y+(w+h+1); + rect.left = x-(w+h+1); + rect.right = x+(w+h+1); + myInvalidateRect( d, &rect ); + } + } + DeleteObject( newFont ); + fp->lfHeight = oldLfHeight; +} + +static const char * wCurFont( void ) +{ + return logFont.lfFaceName; +} + +void wInitializeFonts() +{ +} + +wFont_p wStandardFont( int family, wBool_t bold, wBool_t italic ) +{ + if (family == F_TIMES) + return ×Font[bold][italic]; + else if (family == F_HELV) + return &helvFont[bold][italic]; + else + return NULL; +} + +void wSelectFont( const char * title ) +{ + doChooseFont(); +} + + +wFontSize_t wSelectedFontSize( void ) +{ + return fontSize; +} + +void wSetSelectedFontSize(int size) +{ + fontSize = (wFontSize_t)size; +} + +/* + ***************************************************************************** + * + * Misc + * + ***************************************************************************** + */ + + + +void wDrawFilledRectangle( + wDraw_p d, + wPos_t px, + wPos_t py, + wPos_t sx, + wPos_t sy, + wDrawColor color, + wDrawOpts opts ) +{ + RECT rect; + if (d == NULL) + return; + setDrawBrush( d->hDc, d, color, opts ); + rect.left = XINCH2PIX(d,px); + rect.right = XINCH2PIX(d,px+sx); + rect.top = YINCH2PIX(d,py+sy); + rect.bottom = YINCH2PIX(d,py); + if ( rect.right < 0 || + rect.bottom < 0 ) + return; + if ( rect.left < 0 ) + rect.left = 0; + if ( rect.top < 0 ) + rect.top = 0; + if ( rect.left > d->w || + rect.top > d->h ) + return; + if ( rect.right > d->w ) + rect.right = d->w; + if ( rect.bottom > d->h ) + rect.bottom = d->h; + Rectangle( d->hDc, rect.left, rect.top, rect.right, rect.bottom ); + if (d->hWnd) { + rect.top--; + rect.left--; + rect.bottom++; + rect.right++; + myInvalidateRect( d, &rect ); + } +} + +#ifdef DRAWFILLPOLYLOG +static FILE * logF; +#endif +static int wFillPointsMax = 0; +static POINT * wFillPoints; + +static void addPoint( + int * pk, + POINT * pp, + RECT * pr ) +{ +#ifdef DRAWFILLPOLYLOG +fprintf( logF, " q[%d] = {%d,%d}\n", *pk, pp->x, pp->y ); +#endif + if ( *pk > 0 && + wFillPoints[(*pk)-1].x == pp->x && wFillPoints[(*pk)-1].y == pp->y ) + return; + wFillPoints[ (*pk)++ ] = *pp; + if (pp->x<pr->left) + pr->left = pp->x; + if (pp->x>pr->right) + pr->right = pp->x; + if (pp->y<pr->top) + pr->top = pp->y; + if (pp->y>pr->bottom) + pr->bottom = pp->y; +} + +void wDrawFilledPolygon( + wDraw_p d, + wPos_t p[][2], + int cnt, + wDrawColor color, + wDrawOpts opts ) +{ + RECT rect; + int i, k; + POINT p0, p1, q0, q1; + static POINT zero = { 0, 0 }; + wBool_t p1Clipped; + + if (d == NULL) + return; + if (cnt*2 > wFillPointsMax) { + wFillPoints = realloc( wFillPoints, cnt * 2 * sizeof *(POINT*)NULL ); + wFillPointsMax = cnt*2; + } + setDrawBrush( d->hDc, d, color, opts ); + p1.x = rect.left = rect.right = XINCH2PIX(d,p[cnt-1][0]-1); + p1.y = rect.top = rect.bottom = YINCH2PIX(d,p[cnt-1][1]+1); +#ifdef DRAWFILLPOLYLOG +logF = fopen( "log.txt", "a" ); +fprintf( logF, "\np[%d] = {%d,%d}\n", cnt-1, p1.x, p1.y ); +#endif + p1Clipped = FALSE; + for ( i=k=0; i<cnt; i++ ) { + p0 = p1; + p1.x = XINCH2PIX(d,p[i][0]-1); + p1.y = YINCH2PIX(d,p[i][1]+1); +#ifdef DRAWFILLPOLYLOG +fprintf( logF, "p[%d] = {%d,%d}\n", i, p1.x, p1.y ); +#endif + q0 = p0; + q1 = p1; + if ( clip0( &q0, &q1, NULL ) ) { +#ifdef DRAWFILLPOLYLOG +fprintf( logF, " clip( {%d,%d} {%d,%d} ) = {%d,%d} {%d,%d}\n", p0.x, p0.y, p1.x, p1.y, q0.x, q0.y, q1.x, q1.y ); +#endif + if ( q0.x != p0.x || q0.y != p0.y ) { + if ( k > 0 && ( q0.x > q0.y ) != ( wFillPoints[k-1].x > wFillPoints[k-1].y ) ) + addPoint( &k, &zero, &rect ); + addPoint( &k, &q0, &rect ); + } + addPoint( &k, &q1, &rect ); + p1Clipped = ( q1.x != p1.x || q1.y != p1.y ); + } + } + if ( p1Clipped && + ( wFillPoints[k-1].x > wFillPoints[k-1].y ) != ( wFillPoints[0].x > wFillPoints[0].y ) ) + addPoint( &k, &zero, &rect ); +#ifdef DRAWFILLPOLYLOG +fflush( logF ); +fclose( logF ); +#endif + if ( k <= 2 ) + return; + Polygon( d->hDc, wFillPoints, k ); + if (d->hWnd) { + rect.top--; + rect.left--; + rect.bottom++; + rect.right++; + myInvalidateRect( d, &rect ); + } +} + +#define MAX_FILLCIRCLE_POINTS (30) +void wDrawFilledCircle( + wDraw_p d, + wPos_t x, + wPos_t y, + wPos_t r, + wDrawColor color, + wDrawOpts opts ) +{ + POINT p0, p1; + RECT rect; + static wPos_t circlePts[MAX_FILLCIRCLE_POINTS][2]; + int inx, cnt; + double dang; + + p0.x = XINCH2PIX(d,x-r); + p0.y = YINCH2PIX(d,y+r)+1; + p1.x = XINCH2PIX(d,x+r); + p1.y = YINCH2PIX(d,y-r)+1; + + setDrawBrush( d->hDc, d, color, opts ); + if ( noNegDrawArgs > 0 && ( p0.x < 0 || p0.y < 0 ) ) { + if ( r > MAX_FILLCIRCLE_POINTS ) + cnt = MAX_FILLCIRCLE_POINTS; + else if ( r > 8 ) + cnt = r; + else + cnt = 8; + dang = 360.0/cnt; + for ( inx=0; inx<cnt; inx++ ) { + circlePts[inx][0] = x + (int)(r * mswcos( inx*dang ) + 0.5 ); + circlePts[inx][1] = y + (int)(r * mswsin( inx*dang ) + 0.5 ); + } + wDrawFilledPolygon( d, circlePts, cnt, color, opts ); + } else { + Ellipse( d->hDc, p0.x, p0.y, p1.x, p1.y ); + if (d->hWnd) { + rect.top = p0.y; + rect.bottom = p1.y; + rect.left = p0.x; + rect.right = p1.x; + myInvalidateRect( d, &rect ); + } + } +} + +/* + ***************************************************************************** + * + * Misc + * + ***************************************************************************** + */ + + +void wDrawSaveImage( + wDraw_p bd ) +{ + if ( bd->hBmBackup ) { + SelectObject( bd->hDcBackup, bd->hBmBackupOld ); + DeleteObject( bd->hBmBackup ); + bd->hBmBackup = (HBITMAP)0; + } + if ( bd->hDcBackup == (HDC)0 ) + bd->hDcBackup = CreateCompatibleDC( bd->hDc ); + bd->hBmBackup = CreateCompatibleBitmap( bd->hDc, bd->w, bd->h ); + bd->hBmBackupOld = SelectObject( bd->hDcBackup, bd->hBmBackup ); + BitBlt( bd->hDcBackup, 0, 0, bd->w, bd->h, bd->hDc, 0, 0, SRCCOPY ); +} + +void wDrawRestoreImage( + wDraw_p bd ) +{ + if ( bd->hBmBackup == (HBITMAP)0 ) { + mswFail( "wDrawRestoreImage: hBmBackup == 0" ); + return; + } + BitBlt( bd->hDc, 0, 0, bd->w, bd->h, bd->hDcBackup, 0, 0, SRCCOPY ); + InvalidateRect( bd->hWnd, NULL, FALSE ); +} + + +void wDrawClear( wDraw_p d ) +{ + RECT rect; + SetROP2( d->hDc, R2_WHITE ); + Rectangle( d->hDc, 0, 0, d->w, d->h ); + if (d->hWnd) { + rect.top = 0; + rect.bottom = d->h; + rect.left = 0; + rect.right = d->w; + InvalidateRect( d->hWnd, &rect, FALSE ); + } +} + + +void wDrawSetSize( + wDraw_p d, + wPos_t width, + wPos_t height ) +{ + d->w = width; + d->h = height; + if (!SetWindowPos( d->hWnd, HWND_TOP, 0, 0, + d->w, d->h, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("wDrawSetSize: SetWindowPos"); + } + /*wRedraw( d );*/ +} + + +void wDrawGetSize( + wDraw_p d, + wPos_t * width, + wPos_t * height ) +{ + *width = d->w-2; + *height = d->h-2; +} + + +void * wDrawGetContext( wDraw_p d ) +{ + return d->data; +} + + +double wDrawGetDPI( wDraw_p d ) +{ + return d->DPI; +} + +double wDrawGetMaxRadius( wDraw_p d ) +{ + return 4096.0; +} + +void wDrawClip( + wDraw_p d, + wPos_t x, + wPos_t y, + wPos_t w, + wPos_t h ) +{ + int ix0, iy0, ix1, iy1; + HRGN hRgnClip; + ix0 = XINCH2PIX(d,x); + iy0 = YINCH2PIX(d,y); + ix1 = XINCH2PIX(d,x+w); + iy1 = YINCH2PIX(d,y+h); + /* Note: Ydim is upside down so iy1<iy0 */ + hRgnClip = CreateRectRgn( ix0, iy1, ix1, iy0 ); + SelectClipRgn( d->hDc, hRgnClip ); + DeleteObject( hRgnClip ); +} + + +void wRedraw( wDraw_p d ) +{ + wDrawClear( d ); + if (d->drawRepaint) + d->drawRepaint( d, d->data, 0, 0 ); +} + +/* + ***************************************************************************** + * + * BitMap + * + ***************************************************************************** + */ + +struct wDrawBitMap_t { + wDrawBitMap_p next; + wPos_t x; + wPos_t y; + wPos_t w; + wPos_t h; + char * bmx; + wDrawColor color; + HBITMAP bm; + }; +wDrawBitMap_p bmRoot = NULL; + + +void wDrawBitMap( + wDraw_p d, + wDrawBitMap_p bm, + wPos_t px, + wPos_t py, + wDrawColor dc, + wDrawOpts dopt ) +{ + HDC bmDc, hDc; + HBITMAP oldBm; + DWORD mode; + int x0, y0; + RECT rect; + + x0 = XINCH2PIX(d,px-bm->x); + y0 = YINCH2PIX(d,py-bm->y+bm->h); +#ifdef LATER + if ( noNegDrawArgs > 0 && ( x0 < 0 || y0 < 0 ) ) + return; +#endif + if (dopt & wDrawOptTemp) { + mode = tmpOp; + } else if (dc == wDrawColorWhite) { + mode = clrOp; + dc = wDrawColorBlack; + } else { + mode = setOp; + } + + if ( bm->color != dc ) { + if ( bm->bm ) + DeleteObject( bm->bm ); + bm->bm = mswCreateBitMap( mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/, RGB( 255, 255, 255 ), + RGB( 255, 255, 255 ), bm->w, bm->h, bm->bmx ); + bm->color = dc; + } + if ( (dopt & wDrawOptNoClip) != 0 && + ( px < 0 || px >= d->w || py < 0 || py >= d->h ) ) { + x0 += d->x; + y0 += d->y; + hDc = GetDC( ((wControl_p)(d->parent))->hWnd ); + bmDc = CreateCompatibleDC( hDc ); + oldBm = SelectObject( bmDc, bm->bm ); + BitBlt( hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, tmpOp ); + SelectObject( bmDc, oldBm ); + DeleteDC( bmDc ); + ReleaseDC( ((wControl_p)(d->parent))->hWnd, hDc ); + return; + } + + bmDc = CreateCompatibleDC( d->hDc ); + setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt ); + oldBm = SelectObject( bmDc, bm->bm ); + BitBlt( d->hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, mode ); + SelectObject( bmDc, oldBm ); + DeleteDC( bmDc ); + if (d->hWnd) { + rect.top = y0-1; + rect.bottom = rect.top+bm->h+1; + rect.left = x0-1; + rect.right = rect.left+bm->w+1; + myInvalidateRect( d, &rect ); + } +} + + +wDrawBitMap_p wDrawBitMapCreate( + wDraw_p d, + int w, + int h, + int x, + int y, + const char * bits ) +{ + wDrawBitMap_p bm; + int bmSize = ((w+7)/8) * h; + bm = (wDrawBitMap_p)malloc( sizeof *bm ); + if (bmRoot == NULL) { + bmRoot = bm; + bm->next = NULL; + } else { + bm->next = bmRoot; + bmRoot = bm; + } + bm->x = x; + bm->y = y; + bm->w = w; + bm->h = h; + bm->bmx = malloc( bmSize ); + bm->bm = (HBITMAP)0; + bm->color = -1; + memcpy( bm->bmx, bits, bmSize ); + /*bm->bm = mswCreateBitMap( GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), w, h, bits );*/ + return bm; +} + +/* + ***************************************************************************** + * + * Create + * + ***************************************************************************** + */ + +int doSetFocus = 1; + +long FAR PASCAL XEXPORT mswDrawPush( + HWND hWnd, + UINT message, + UINT wParam, + LONG lParam ) +{ +#ifdef WIN32 + long inx = GetWindowLong( hWnd, GWL_ID ); +#else + short inx = GetWindowWord( hWnd, GWW_ID ); +#endif + wDraw_p b; + short int ix, iy; + wPos_t x, y; + HDC hDc; + PAINTSTRUCT ps; + wAction_t action; + RECT rect; + HWND activeWnd; + HWND focusWnd; + wAccelKey_e extChar; + + switch( message ) { + case WM_CREATE: + b = (wDraw_p)mswMapIndex( inx ); + hDc = GetDC(hWnd); + if ( b->option & BD_DIRECT ) { + b->hDc = hDc; + b->hBm = 0; + b->hBmOld = 0; + } else { + b->hDc = CreateCompatibleDC( hDc ); + b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); + b->hBmOld = SelectObject( b->hDc, b->hBm ); + } + if (mswPalette) { + SelectPalette( b->hDc, mswPalette, 0 ); + RealizePalette( b->hDc ); + } + b->wFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSX ); + b->hFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSY ); + b->DPI = 96.0; /*min( b->wFactor, b->hFactor );*/ + b->hWnd = hWnd; + SetROP2( b->hDc, R2_WHITE ); + Rectangle( b->hDc, 0, 0, b->w, b->h ); + if ( (b->option & BD_DIRECT) == 0 ) { + SetROP2( hDc, R2_WHITE ); + Rectangle( hDc, 0, 0, b->w, b->h ); + ReleaseDC( hWnd, hDc ); + } + break; + case WM_SIZE: + b = (wDraw_p)mswMapIndex( inx ); + ix = LOWORD( lParam ); + iy = HIWORD( lParam ); + b->w = ix+2; + b->h = iy+2; + if (b->hWnd) { + if ( b->option & BD_DIRECT ) { + } else { + hDc = GetDC( b->hWnd ); + b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); + DeleteObject(SelectObject( b->hDc, b->hBm )); + ReleaseDC( b->hWnd, hDc ); + SetROP2( b->hDc, R2_WHITE ); + Rectangle( b->hDc, 0, 0, b->w, b->h ); + } + } + /*if (b->drawResize) + b->drawResize( b, b->size );*/ + if (b->drawRepaint) + b->drawRepaint( b, b->data, 0, 0 ); + return 0; + case WM_MOUSEMOVE: + activeWnd = GetActiveWindow(); + focusWnd = GetFocus(); + if (focusWnd != hWnd) { + b = (wDraw_p)mswMapIndex( inx ); + if (!b) + break; + if ( !((wControl_p)b->parent) ) + break; + if ( ((wControl_p)b->parent)->hWnd != activeWnd ) + break; + } + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + if (message == WM_LBUTTONDOWN) + action = wActionLDown; + else if (message == WM_RBUTTONDOWN) + action = wActionRDown; + else if (message == WM_LBUTTONUP) + action = wActionLUp; + else if (message == WM_RBUTTONUP) + action = wActionRUp; + else { + if ( (wParam & MK_LBUTTON) != 0) + action = wActionLDrag; + else if ( (wParam & MK_RBUTTON) != 0) + action = wActionRDrag; + else + action = wActionMove; + } + b = (wDraw_p)mswMapIndex( inx ); + if (!b) + break; + if (doSetFocus && message != WM_MOUSEMOVE) + SetFocus( ((wControl_p)b->parent)->hWnd ); + if ( (b->option&BD_NOCAPTURE) == 0 ) { + if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN) + SetCapture( b->hWnd ); + else if (message == WM_LBUTTONUP || message == WM_RBUTTONUP) + ReleaseCapture(); + } + ix = LOWORD( lParam ); + iy = HIWORD( lParam ); + x = XPIX2INCH( b, ix ); + y = YPIX2INCH( b, iy ); + if (b->action) + b->action( b, b->data, action, x, y ); + if (b->hWnd) + UpdateWindow(b->hWnd); + return 0; + case WM_CHAR: + b = (wDraw_p)mswMapIndex( inx ); + extChar = wAccelKey_None; + if (lParam & 0x01000000L) + switch( wParam ) { + case VK_DELETE: extChar = wAccelKey_Del; break; + case VK_INSERT: extChar = wAccelKey_Ins; break; + case VK_HOME: extChar = wAccelKey_Home; break; + case VK_END: extChar = wAccelKey_End; break; + case VK_PRIOR: extChar = wAccelKey_Pgup; break; + case VK_NEXT: extChar = wAccelKey_Pgdn; break; + case VK_UP: extChar = wAccelKey_Up; break; + case VK_DOWN: extChar = wAccelKey_Down; break; + case VK_RIGHT: extChar = wAccelKey_Right; break; + case VK_LEFT: extChar = wAccelKey_Left; break; + case VK_BACK: extChar = wAccelKey_Back; break; + /*case VK_F1: extChar = wAccelKey_F1; break;*/ + case VK_F2: extChar = wAccelKey_F2; break; + case VK_F3: extChar = wAccelKey_F3; break; + case VK_F4: extChar = wAccelKey_F4; break; + case VK_F5: extChar = wAccelKey_F5; break; + case VK_F6: extChar = wAccelKey_F6; break; + case VK_F7: extChar = wAccelKey_F7; break; + case VK_F8: extChar = wAccelKey_F8; break; + case VK_F9: extChar = wAccelKey_F9; break; + case VK_F10: extChar = wAccelKey_F10; break; + case VK_F11: extChar = wAccelKey_F11; break; + case VK_F12: extChar = wAccelKey_F12; break; + } + if (b && b->action) { + if (extChar != wAccelKey_None) + b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), 0, 0 ); + else + b->action( b, b->data, wActionText + ( wParam << 8 ), 0, 0 ); + } + return 0; + + case WM_PAINT: + b = (wDraw_p)mswMapIndex( inx ); + if (b && b->type == B_DRAW) { + if (GetUpdateRect( b->hWnd, &rect, FALSE )) { + hDc = BeginPaint( hWnd, &ps ); + if ( b->hasPalette ) { + int winPaletteClock = mswGetPaletteClock(); + if ( b->paletteClock < winPaletteClock ) { + RealizePalette( hDc ); + b->paletteClock = winPaletteClock; + } + } + BitBlt( hDc, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, + b->hDc, rect.left, rect.top, + SRCCOPY ); + EndPaint( hWnd, &ps ); + } + } + break; + case WM_DESTROY: + b = (wDraw_p)mswMapIndex( inx ); + if (b && b->type == B_DRAW) { + if (b->hDc) { + DeleteDC( b->hDc ); + b->hDc = (HDC)0; + } + if (b->hDcBackup) { + DeleteDC( b->hDcBackup ); + b->hDcBackup = (HDC)0; + } + } + break; + default: + break; + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static LRESULT drawMsgProc( wDraw_p b, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + wAction_t action; + + switch( message ) { + case WM_MOUSEWHEEL: + /* handle mouse wheel events */ + /* fwKeys = GET_KEYSTATE_WPARAM(wParam); modifier keys are currently ignored */ + if ( GET_WHEEL_DELTA_WPARAM(wParam) > 0 ) { + action = wActionWheelUp; + } else { + action = wActionWheelDown; + } + if (b->action) + b->action( b, b->data, action, 0, 0 ); + return 0; + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static void drawDoneProc( wControl_p b ) +{ + wDraw_p d = (wDraw_p)b; + if (d->hBm) { + SelectObject( d->hDc, d->hBmOld ); + DeleteObject( d->hBm ); + d->hBm = (HBITMAP)0; + } + if (d->hPen) { + SelectObject( d->hDc, GetStockObject( BLACK_PEN ) ); + DeleteObject( d->hPen ); + d->hPen = (HPEN)0; + } + if (d->hBrush) { + SelectObject( d->hDc, GetStockObject( BLACK_BRUSH) ); + DeleteObject( d->hBrush ); + d->hBrush = (HBRUSH)0; + } + if (d->hDc) { + DeleteDC( d->hDc ); + d->hDc = (HDC)0; + } + if ( d->hDcBackup ) { + DeleteDC( d->hDcBackup ); + d->hDcBackup = (HDC)0; + } + while (bmRoot) { + if (bmRoot->bm) + DeleteObject( bmRoot->bm ); + bmRoot = bmRoot->next; + } +} + + +static callBacks_t drawCallBacks = { + NULL, + drawDoneProc, + (messageCallback_p)drawMsgProc }; + +wDraw_p drawList = NULL; + + +void mswRedrawAll( void ) +{ + wDraw_p p; + for ( p=drawList; p; p=p->drawNext ) { + if (p->drawRepaint) + p->drawRepaint( p, p->data, 0, 0 ); + } +} + + +void mswRepaintAll( void ) +{ + wDraw_p b; + HDC hDc; + RECT rect; + PAINTSTRUCT ps; + + for ( b=drawList; b; b=b->drawNext ) { + if (GetUpdateRect( b->hWnd, &rect, FALSE )) { + hDc = BeginPaint( b->hWnd, &ps ); + BitBlt( hDc, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, + b->hDc, rect.left, rect.top, + SRCCOPY ); + EndPaint( b->hWnd, &ps ); + } + } +} + + +wDraw_p wDrawCreate( + wWin_p parent, + wPos_t x, + wPos_t y, + const char * helpStr, + long option, + wPos_t w, + wPos_t h, + void * data, + wDrawRedrawCallBack_p redrawProc, + wDrawActionCallBack_p action ) +{ + wDraw_p d; + RECT rect; + int index; + HDC hDc; + + if ( noNegDrawArgs < 0 ) { + wPrefGetInteger( "msw tweak", "NoNegDrawArgs", &noNegDrawArgs, 0 ); + wPrefGetInteger( "msw tweak", "NoFlatEndCaps", &noFlatEndCaps, 0 ); + } + + d = mswAlloc( parent, B_DRAW, NULL, sizeof *d, data, &index ); + mswComputePos( (wControl_p)d, x, y ); + d->w = w; + d->h = h; + d->drawRepaint = NULL; + d->action = action; + d->option = option; + + d->hWnd = CreateWindow( mswDrawWindowClassName, NULL, + WS_CHILDWINDOW|WS_VISIBLE|WS_BORDER, + d->x, d->y, w, h, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + + if (d->hWnd == (HWND)0) { + mswFail( "CreateWindow(DRAW)" ); + return d; + } + + GetWindowRect( d->hWnd, &rect ); + + d->w = rect.right - rect.left; + d->h = rect.bottom - rect.top; + d->drawRepaint = redrawProc; + /*if (d->drawRepaint) + d->drawRepaint( d, d->data, 0.0, 0.0 );*/ + + mswAddButton( (wControl_p)d, FALSE, helpStr ); + mswCallBacks[B_DRAW] = &drawCallBacks; + d->drawNext = drawList; + drawList = d; + if (mswPalette) { + hDc = GetDC( d->hWnd ); + d->hasPalette = TRUE; + SelectPalette( hDc, mswPalette, 0 ); + ReleaseDC( d->hWnd, hDc ); + } + return d; +} + +/* + ***************************************************************************** + * + * Bitmaps + * + ***************************************************************************** + */ + +wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes ) +{ + wDraw_p d; + HDC hDc; + + d = (wDraw_p)calloc(1,sizeof *d); + d->type = B_DRAW; + d->shown = TRUE; + d->x = 0; + d->y = 0; + d->w = w; + d->h = h; + d->drawRepaint = NULL; + d->action = NULL; + d->option = 0; + + hDc = GetDC(mswHWnd); + d->hDc = CreateCompatibleDC( hDc ); + if ( d->hDc == (HDC)0 ) { + wNoticeEx( NT_ERROR, "CreateBitMap: CreateDC fails", "Ok", NULL ); + return FALSE; + } + d->hBm = CreateCompatibleBitmap( hDc, d->w, d->h ); + if ( d->hBm == (HBITMAP)0 ) { + wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM fails", "Ok", NULL ); + return FALSE; + } + d->hasPalette = (GetDeviceCaps(hDc,RASTERCAPS ) & RC_PALETTE) != 0; + ReleaseDC( mswHWnd, hDc ); + d->hBmOld = SelectObject( d->hDc, d->hBm ); + if (mswPalette) { + SelectPalette( d->hDc, mswPalette, 0 ); + RealizePalette( d->hDc ); + } + d->wFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSX ); + d->hFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSY ); + d->DPI = 96.0; /*min( d->wFactor, d->hFactor );*/ + d->hWnd = 0; + SetROP2( d->hDc, R2_WHITE ); + Rectangle( d->hDc, 0, 0, d->w, d->h ); + return d; +} + +wBool_t wBitMapDelete( wDraw_p d ) +{ + if (d->hPen) { + SelectObject( d->hDc, GetStockObject( BLACK_PEN ) ); + DeleteObject( d->hPen ); + d->hPen = (HPEN)0; + } + if (d->hBm) { + SelectObject( d->hDc, d->hBmOld ); + DeleteObject( d->hBm ); + d->hBm = (HBITMAP)0; + } + if (d->hDc) { + DeleteDC( d->hDc ); + d->hDc = (HDC)0; + } + free(d); + return TRUE; +} + +wBool_t wBitMapWriteFile( wDraw_p d, const char * fileName ) +{ + char *pixels; + int j, ww, chunk; + FILE * f; + BITMAPFILEHEADER bmfh; + struct { + BITMAPINFOHEADER bmih; + RGBQUAD colors[256]; + } bmi; + int rc; + + if ( d->hBm == 0) + return FALSE; + f = wFileOpen( fileName, "wb" ); + if (!f) { + wNoticeEx( NT_ERROR, fileName, "Ok", NULL ); + return FALSE; + } + ww = ((d->w +3) / 4) * 4; + bmfh.bfType = 'B'+('M'<<8); + bmfh.bfSize = (long)(sizeof bmfh) + (long)(sizeof bmi.bmih) + (long)(sizeof bmi.colors) + (long)ww * (long)(d->h); + bmfh.bfReserved1 = 0; + bmfh.bfReserved2 = 0; + bmfh.bfOffBits = sizeof bmfh + sizeof bmi.bmih + sizeof bmi.colors; + fwrite( &bmfh, 1, sizeof bmfh, f ); + bmi.bmih.biSize = sizeof bmi.bmih; + bmi.bmih.biWidth = d->w; + bmi.bmih.biHeight = d->h; + bmi.bmih.biPlanes = 1; + bmi.bmih.biBitCount = 8; + bmi.bmih.biCompression = BI_RGB; + bmi.bmih.biSizeImage = 0; + bmi.bmih.biXPelsPerMeter = 75*(10000/254); + bmi.bmih.biYPelsPerMeter = 75*(10000/254); + bmi.bmih.biClrUsed = bmi.bmih.biClrImportant = mswGetColorList( bmi.colors ); + SelectObject( d->hDc, d->hBmOld ); + rc = GetDIBits( d->hDc, d->hBm, 0, 1, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS ); + if ( rc == 0 ) { + wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bitmapinfo from Bitmap", "Ok", NULL ); + return FALSE; + } + bmi.bmih.biClrUsed = 256; + fwrite( &bmi.bmih, 1, sizeof bmi.bmih, f ); + fwrite( bmi.colors, 1, sizeof bmi.colors, f ); + chunk = 32000/ww; + pixels = (char*)malloc( ww*chunk ); + if ( pixels == NULL ) { + wNoticeEx( NT_ERROR, "WriteBitMap: no memory", "OK", NULL ); + return FALSE; + } + for (j=0;j<d->h;j+=chunk) { + if (j+chunk>d->h) + chunk = d->h-j; + rc = GetDIBits( d->hDc, d->hBm, j, chunk, pixels, (BITMAPINFO*)&bmi, DIB_RGB_COLORS ); + if ( rc == 0 ) + if ( rc == 0 ) { + wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bits from Bitmap", "Ok", NULL ); + return FALSE; + } + rc = fwrite( pixels, 1, ww*chunk, f ); + if (rc != ww*chunk) { + wNoticeEx( NT_ERROR, "WriteBitMap: Bad fwrite", "Ok", NULL); + } + } + free( pixels ); + SelectObject( d->hDc, d->hBm ); + fclose( f ); + return TRUE; +} + diff --git a/app/wlib/mswlib/mswedit.c b/app/wlib/mswlib/mswedit.c new file mode 100644 index 0000000..5bb26ec --- /dev/null +++ b/app/wlib/mswlib/mswedit.c @@ -0,0 +1,726 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <stdio.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + + +struct wString_t { + WOBJ_COMMON + char * valueP; + wIndex_t valueL; + wStringCallBack_p action; + }; + +struct wInteger_t { + WOBJ_COMMON + long low, high; + long * valueP; + long oldValue; + wIntegerCallBack_p action; + }; + +struct wFloat_t { + WOBJ_COMMON + double low, high; + double * valueP; + double oldValue; + wFloatCallBack_p action; + }; + + +static XWNDPROC oldEditProc = NULL; +static XWNDPROC newEditProc; +static void triggerString( wControl_p b ); +#ifdef LATER +static void triggerInteger( wControl_p b ); +static void triggerFloat( wControl_p b ); +#endif + + +long FAR PASCAL _export pushEdit( + HWND hWnd, + UINT message, + 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 ); + + 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; + + } + return CallWindowProc( oldEditProc, hWnd, message, wParam, lParam ); +} + +/* + ***************************************************************************** + * + * String Boxes + * + ***************************************************************************** + */ + + +void wStringSetValue( + wString_p b, + const char * arg ) +{ + WORD len = strlen( arg ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)arg ); +#ifdef WIN32 + SendMessage( b->hWnd, EM_SETSEL, len, len ); + SendMessage( b->hWnd, EM_SCROLLCARET, 0, 0L ); +#else + SendMessage( b->hWnd, EM_SETSEL, 0, MAKELPARAM(len,len) ); +#endif + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); +} + + +void wStringSetWidth( + wString_p b, + wPos_t w ) +{ + int rc; + b->w = w; + rc = SetWindowPos( b->hWnd, HWND_TOP, 0, 0, + b->w, b->h, SWP_NOMOVE|SWP_NOZORDER ); +} + + +const char * wStringGetValue( + wString_p b ) +{ + static char buff[256]; + SendMessage( b->hWnd, WM_GETTEXT, sizeof buff, (DWORD)buff ); + return buff; +} + + +static void triggerString( + wControl_p b ) +{ + wString_p bs = (wString_p)b; + int cnt; + + 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 ); + } +} + + +LRESULT stringProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + 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; + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static callBacks_t stringCallBacks = { + mswRepaintLabel, + NULL, + stringProc }; + + +wString_p wStringCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + char *valueP, + wIndex_t valueL, + wStringCallBack_p action, + void *data ) +{ + wString_p b; + RECT rect; + int index; + DWORD style = 0; + + b = (wString_p)mswAlloc( parent, B_STRING, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->valueP = valueP; + b->valueL = valueL; + b->labelY += 2; + b->action = action; + if (option & BO_READONLY) + style |= ES_READONLY; + +#ifdef WIN32 + b->hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); +#else + b->hWnd = CreateWindow( "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); +#endif + if (b->hWnd == NULL) { + mswFail("CreateWindow(STRING)"); + 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 ); + + if (b->valueP) { + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)b->valueP ); + } + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[B_STRING] = &stringCallBacks; + mswChainFocus( (wControl_p)b ); + return b; +} +#ifdef LATER + +/* + ***************************************************************************** + * + * Integer Value Boxes + * + ***************************************************************************** + */ + + +#define MININT ((long)0x80000000) +#define MAXINT ((long)0x7FFFFFFF) + + +void wIntegerSetValue( + wInteger_p b, + long arg ) +{ + b->oldValue = arg; + wsprintf( mswTmpBuff, "%ld", arg ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); +} + + +long wIntegerGetValue( + wInteger_p b ) +{ + return b->oldValue; +} + + +static void triggerInteger( + wControl_p b ) +{ + wInteger_p bi = (wInteger_p)b; + int cnt; + long value; + char * cp; + + if (bi->action) { + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bi->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0 ) + return; + value = strtol( mswTmpBuff, &cp, 10 ); + if (*cp != '\0' || value < bi->low || value > bi->high ) + return; + if (bi->oldValue == value) + return; + if (bi->valueP) + *bi->valueP = value; + bi->oldValue = value; + bi->action( value, bi->data ); + } +} + + +LRESULT integerProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wInteger_p bi = (wInteger_p)b; + int inx; + int cnt; + long value; + char * cp; + wBool_t ok; + int modified; + + switch( message ) { + + case WM_COMMAND: + switch (WCMD_PARAM_NOTF) { + case EN_KILLFOCUS: + ok = TRUE; + modified = (int)SendMessage( bi->hWnd, (UINT)EM_GETMODIFY, 0, 0L ); + if (!modified) + break; + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bi->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0 && 0 >= bi->low && 0 <= bi->high ) { + value = 0; + } else { + value = strtol( mswTmpBuff, &cp, 10 ); + if (*cp != '\0' || value < bi->low || value > bi->high ) { + inx = GetWindowWord( bi->hWnd, GWW_ID ); + if (wWinIsVisible(bi->parent)) { + PostMessage( ((wControl_p)(bi->parent))->hWnd, + WM_NOTVALID, inx, 0L ); + return TRUE; + } else { + if (value < bi->low) + value = bi->low; + else + value = bi->high; + sprintf( mswTmpBuff, "%ld", value ); + SendMessage( bi->hWnd, (UINT)WM_SETTEXT, 0, + (DWORD)(LPSTR)mswTmpBuff ); + } + } + } + bi->oldValue = value; + if (bi->valueP) + *bi->valueP = value; + if (bi->action) { + bi->action( value, bi->data ); + mswSetTrigger( NULL, NULL ); + } + SendMessage( bi->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L ); + } + break; + + case WM_NOTVALID: + wsprintf( mswTmpBuff, "Please enter a value between %ld and %ld", + bi->low, bi->high ); + if (bi->low > MININT && bi->high < MAXINT) + sprintf( mswTmpBuff, + "Please enter an integer value between %ld and %ld", + bi->low, bi->high ); + else if (bi->low > MININT) + sprintf( mswTmpBuff, + "Please enter an integer value greater or equal to %ld", + bi->low ); + else if (bi->high < MAXINT) + sprintf( mswTmpBuff, + "Please enter an integer value less or equal to %ld", + bi->high ); + else + strcpy( mswTmpBuff, "Please enter an integer value" ); + MessageBox( bi->hWnd, mswTmpBuff, "Invalid entry", MB_OK ); + SetFocus( bi->hWnd ); +#ifdef WIN32 + SendMessage( bi->hWnd, EM_SETSEL, 0, 0x7fff ); + SendMessage( bi->hWnd, EM_SCROLLCARET, 0, 0L ); +#else + SendMessage( bi->hWnd, EM_SETSEL, 0, MAKELONG(0,0x7fff) ); +#endif + return TRUE; + + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static callBacks_t integerCallBacks = { + mswRepaintLabel, + NULL, + integerProc }; + + +wInteger_p wIntegerCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + long low, + long high, + long *valueP, + wIntegerCallBack_p action, + void *data ) +{ + wInteger_p b; + RECT rect; + int index; + DWORD style = 0; + + b = mswAlloc( parent, B_INTEGER, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->low = low; + b->high = high; + b->valueP = valueP; + b->labelY += 2; + b->action = action; + if (option & BO_READONLY) + style |= ES_READONLY; + + b->hWnd = CreateWindow( "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(INTEGER)"); + 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 ); + + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + if (b->valueP) { + wsprintf( mswTmpBuff, "%ld", *b->valueP ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + b->oldValue = *b->valueP; + } else + b->oldValue = 0; + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[ B_INTEGER ] = &integerCallBacks; + mswChainFocus( (wControl_p)b ); + return b; +} + +/* + ***************************************************************************** + * + * Floating Point Value Boxes + * + ***************************************************************************** + */ + + +#define MINFLT (-1000000) +#define MAXFLT (1000000) + + + +void wFloatSetValue( + wFloat_p b, + double arg ) +{ + b->oldValue = arg; + sprintf( mswTmpBuff, "%0.3f", arg ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); +} + + +double wFloatGetValue( + wFloat_p b ) +{ + return b->oldValue; +} + + +static void triggerFloat( + wControl_p b ) +{ + wFloat_p bf = (wFloat_p)b; + int cnt; + double value; + char * cp; + + if (bf->action) { + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bf->hWnd, (UINT)EM_GETLINE, 0, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0) + return; + value = strtod( mswTmpBuff, &cp ); + if (*cp != '\0' || value < bf->low || value > bf->high ) + return; + if (bf->oldValue == value) + return; + bf->oldValue = value; + if (bf->valueP) + *bf->valueP = value; + bf->action( wFloatGetValue(bf), bf->data ); + } +} + + +LRESULT floatProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wFloat_p bf = (wFloat_p)b; + int inx; + int cnt; + double value; + char * cp; + wBool_t ok; + int modified; + + switch( message ) { + + case WM_COMMAND: + switch (HIWORD(lParam)) { + case EN_KILLFOCUS: + ok = TRUE; + modified = (int)SendMessage( bf->hWnd, (UINT)EM_GETMODIFY, 0, 0L ); + if (!modified) + break; + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bf->hWnd, (UINT)EM_GETLINE, 0, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0 && 0 >= bf->low && 0 <= bf->high ) { + value = 0; + } else { + value = strtod( mswTmpBuff, &cp ); + if (*cp != '\0' || value < bf->low || value > bf->high ) { + inx = GetWindowWord( bf->hWnd, GWW_ID ); + if (wWinIsVisible(bf->parent)) { + PostMessage( ((wControl_p)(bf->parent))->hWnd, + WM_NOTVALID, inx, 0L ); + return TRUE; + } else { + if (value < bf->low) + value = bf->low; + else + value = bf->high; + sprintf( mswTmpBuff, "%0.3f", value ); + SendMessage( bf->hWnd, (UINT)WM_SETTEXT, 0, + (DWORD)(LPSTR)mswTmpBuff ); + } + } + } + bf->oldValue = value; + if (bf->valueP) + *bf->valueP = value; + if (bf->action) { + bf->action( value, bf->data ); + mswSetTrigger( NULL, NULL ); + } + SendMessage( bf->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L ); + } + break; + + case WM_NOTVALID: + if (bf->low > MINFLT && bf->high < MAXFLT) + sprintf( mswTmpBuff, + "Please enter an float value between %0.3f and %0.3f", + bf->low, bf->high ); + else if (bf->low > MINFLT) + sprintf( mswTmpBuff, + "Please enter an float value greater or equal to %0.3f", + bf->low ); + else if (bf->high < MAXFLT) + sprintf( mswTmpBuff, + "Please enter an float value less or equal to %0.3f", + bf->high ); + else + strcpy( mswTmpBuff, "Please enter an float value" ); + MessageBox( bf->hWnd, mswTmpBuff, "Invalid entry", MB_OK ); + SetFocus( bf->hWnd ); +#ifdef WIN32 + SendMessage( bi->hWnd, EM_SETSEL, 0, 0x7fff ); + SendMessage( bi->hWnd, EM_SCROLLCARET, 0, 0L ); +#else + SendMessage( bi->hWnd, EM_SETSEL, 0, MAKELONG(0,0x7fff) ); +#endif + return TRUE; + + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static callBacks_t floatCallBacks = { + mswRepaintLabel, + NULL, + floatProc }; + + +wFloat_p wFloatCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + double low, + double high, + double *valueP, + wFloatCallBack_p action, + void *data ) +{ + wFloat_p b; + RECT rect; + int index; + DWORD style = 0; + + b = mswAlloc( parent, B_FLOAT, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->low = low; + b->high = high; + b->valueP = valueP; + b->labelY += 2; + b->action = action; + if (option & BO_READONLY) + style |= ES_READONLY; + + b->hWnd = CreateWindow( "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(FLOAT)"); + 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 ); + + if (b->valueP) { + b->oldValue = *b->valueP; + } else + b->oldValue = 0.0; + if (b->valueP) + sprintf( mswTmpBuff, "%0.3f", *b->valueP ); + else + strcpy( mswTmpBuff, "0.000" ); + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[ B_FLOAT ] = &floatCallBacks; + mswChainFocus( (wControl_p)b ); + return b; +} +#endif diff --git a/app/wlib/mswlib/mswint.h b/app/wlib/mswlib/mswint.h new file mode 100644 index 0000000..2311415 --- /dev/null +++ b/app/wlib/mswlib/mswint.h @@ -0,0 +1,193 @@ +#include "wlib.h" +#include "mswlib.h" +#include "dynarr.h" +#ifndef WIN32 +/*#define CONTROL3D*/ +#endif +#include "stdio.h" + +#ifdef CONTROL3D +#include "ctl3d.h" +#endif + +#ifdef WIN32 +#ifdef FAR +#undef FAR +#endif +#define FAR +#define _export +#define MoveTo(HDC,X,Y) MoveToEx(HDC,X,Y,NULL) +#define READ (0) +#define WRITE (1) +#define XEXPORT +#define XWNDPROC WNDPROC +#define WCMD_PARAM_HWND lParam +#define WCMD_PARAM_NOTF HIWORD(wParam) +#define WCMD_PARAM_ID LOWORD(wParam) +#define WSCROLL_PARAM_CODE LOWORD(wParam) +#define WSCROLL_PARAM_NPOS HIWORD(wParam) +#define WSCROLL_PARAM_HWND lParam +#else +#define XEXPORT _export +#define XWNDPROC FARPROC +#define WCMD_PARAM_HWND LOWORD(lParam) +#define WCMD_PARAM_NOTF HIWORD(lParam) +#define WCMD_PARAM_ID wParam +#define WSCROLL_PARAM_CODE wParam +#define WSCROLL_PARAM_NPOS LOWORD(lParam) +#define WSCROLL_PARAM_HWND HIWORD(lParam) +#endif + +#define CAST_AWAY_CONST (char *) + +#define BOOL_T wBool_t +#define POS_T wPos_t +#define INDEX_T wIndex_t +#define INTEGER_T wInteger_t + +typedef enum { + W_MAIN, W_POPUP, + B_BUTTON, B_STRING, B_INTEGER, B_FLOAT, + B_LIST, B_DROPLIST, B_COMBOLIST, + B_RADIO, B_TOGGLE, + B_DRAW, B_TEXT, B_MESSAGE, B_LINES, + B_MENUITEM, B_CHOICEITEM, B_BOX, + B_BITMAP } wType_e; + +typedef void (*repaintProcCallback_p)( HWND, wControl_p ); +typedef void (*doneProcCallback_p)( wControl_p b ); +typedef LRESULT (*messageCallback_p)( wControl_p, HWND, UINT, WPARAM, LPARAM ); +typedef void (*setTriggerCallback_p)( wControl_p b ); +typedef void (*setBusyCallback_p)( wControl_p, BOOL_T ); +typedef void (*showCallback_p)( wControl_p, BOOL_T ); +typedef void (*setPosCallback_p)( wControl_p, wPos_t, wPos_t ); + +typedef struct { + repaintProcCallback_p repaintProc; + doneProcCallback_p doneProc; + messageCallback_p messageProc; + setBusyCallback_p setBusyProc; + showCallback_p showProc; + setPosCallback_p setPosProc; + } callBacks_t; + +#define CALLBACK_CNT (B_BOX+1) +extern callBacks_t *mswCallBacks[CALLBACK_CNT]; + + +#define WOBJ_COMMON \ + wType_e type; \ + wControl_p next; \ + wControl_p synonym; \ + wWin_p parent; \ + POS_T x, y; \ + POS_T w, h; \ + long option; \ + POS_T labelX, labelY; \ + const char * labelStr; \ + const char * helpStr; \ + const char * tipStr; \ + HWND hWnd; \ + void * data;\ + wControl_p focusChainNext; \ + wBool_t shown; + +struct wControl_t { + WOBJ_COMMON + }; + +typedef struct { + unsigned key; + wDrawColor color; + } wIconColorMap_t; +#define mswIcon_bitmap (1) +#define mswIcon_pixmap (2) + +struct wIcon_t { + int type; + wPos_t w; /**< width */ + wPos_t h; /**< height */ + wDrawColor color; + int colorcnt; /**< number of colors */ + RGBQUAD *colormap; + char *pixels; /**< pointer to pixel information */ + int transparent; /**< index of transparent color */ + }; + +struct wDraw_t { + WOBJ_COMMON + HDC hDc; + double wFactor; + double hFactor; + double DPI; + wDrawRedrawCallBack_p drawRepaint; + wDrawActionCallBack_p action; + HBITMAP hBm; + HPEN hPen; + HBRUSH hBrush; + wDraw_p drawNext; + HBITMAP hBmOld; + wBool_t hasPalette; + int paletteClock; + HBITMAP hBmBackup; + HDC hDcBackup; + HBITMAP hBmBackupOld; + }; + +extern HINSTANCE mswHInst; +extern char mswTmpBuff[1024]; +extern HWND mswHWnd; +extern const char *mswDrawWindowClassName; +char *mswProfileFile; +extern int mswEditHeight; +extern int mswAllowBalloonHelp; +extern HFONT mswOldTextFont; +extern HFONT mswLabelFont; +extern wDrawColor wDrawColorWhite; +extern wDrawColor wDrawColorBlack; +extern long mswThickFont; +extern double mswScale; + +DWORD mswGetBaseStyle( wWin_p ); +char * mswStrdup( const char * ); +HBITMAP mswCreateBitMap( COLORREF, COLORREF, COLORREF, int, int, const char * ); +void mswFail( const char * ); +void mswResize( wWin_p ); +wControl_p mswMapIndex( INDEX_T ); +void mswButtPush( wControl_p ); +void * mswAlloc( wWin_p, wType_e, const char *, int, void *, int * ); +void mswComputePos( wControl_p, wPos_t, wPos_t ); +void mswAddButton( wControl_p, BOOL_T, const char * ); +void mswRepaintLabel( HWND, wControl_p ); +int mswRegister( wControl_p ); +void mswUnregister( int ); +void mswChainFocus( wControl_p ); +void mswSetFocus( wControl_p ); +void mswSetTrigger( wControl_p, setTriggerCallback_p ); +void mswMenuPush( wControl_p ); +void mswCreateCheckBitmaps( void ); +long FAR PASCAL XEXPORT mswDrawPush( HWND, UINT, UINT, LONG ); +#ifdef WIN32 +DWORD GetTextExtent( HDC, CHAR *, UINT ); +#endif +void mswRedrawAll( void ); +void mswRepaintAll( void ); +HDC mswGetPrinterDC( void ); +int mswMenuAccelerator( wWin_p, long ); +void mswMenuMove( wMenu_p, wPos_t, wPos_t ); +void mswRegisterBitMap( HBITMAP ); +void mswFontInit( void ); +void mswInitColorPalette( void ); +void mswPutCustomColors( void ); +COLORREF mswGetColor( wBool_t, wDrawColor ); +int mswGetColorList( RGBQUAD * ); +int mswGetPaletteClock( void ); +HPALETTE mswPalette; +HPALETTE mswCreatePalette( void ); + +/* mswbitmaps.c */ +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 diff --git a/app/wlib/mswlib/mswlines.c b/app/wlib/mswlib/mswlines.c new file mode 100644 index 0000000..be1330d --- /dev/null +++ b/app/wlib/mswlib/mswlines.c @@ -0,0 +1,98 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Lines + * + ***************************************************************************** + */ + +struct wLine_t { + WOBJ_COMMON + int count; + wLines_t * lines; + }; + +static void repaintLines( HWND hWnd, wControl_p b ) +{ + int lastWidth; + HDC hDc; + wLine_p bl = (wLine_p)(b); + wLines_p lp; + HPEN oldPen, newPen; + + lastWidth = -1; + hDc = GetDC( hWnd ); + for (lp=bl->lines; lp<&bl->lines[bl->count]; lp++) { + if (lastWidth != lp->width) { + lastWidth = lp->width; + newPen = CreatePen( PS_SOLID, lastWidth, RGB(0,0,0) ); + oldPen = SelectObject( hDc, newPen ); + DeleteObject( oldPen ); + } + MoveTo( hDc, lp->x0, lp->y0 ); + LineTo( hDc, lp->x1, lp->y1 ); + } + ReleaseDC( hWnd, hDc ); +} + + +static callBacks_t linesCallBacks = { + repaintLines, + NULL, + NULL }; + + +wLine_p wLineCreate( + wWin_p parent, + const char * labelStr, + int count, + wLines_t * lines ) +{ + wLine_p b; + wLines_p lp; + POS_T minX, maxX, minY, maxY; + int index; + + if (count <= 0) + return NULL; + b = (wLine_p)mswAlloc( parent, B_LINES, labelStr, sizeof *b, NULL, &index ); + b->count = count; + b->lines = lines; + + lp = lines; + minX = maxX = lp->x0; + minY = maxY = lp->y0; + for (lp=lines; lp<&b->lines[count]; lp++) { + if (minX > lp->x0) + minX = lp->x0; + if (maxX < lp->x0) + maxX = lp->x0; + if (minY > lp->y0) + minY = lp->y0; + if (maxY < lp->y0) + maxY = lp->y0; + if (minX > lp->x1) + minX = lp->x1; + if (maxX < lp->x1) + maxX = lp->x1; + if (minY > lp->y1) + minY = lp->y1; + if (maxY < lp->y1) + maxY = lp->y1; + } + b->x = minX; + b->y = minY; + b->w = maxX-minX; + b->h = maxY-minY; + mswAddButton( (wControl_p)b, FALSE, NULL ); + mswCallBacks[B_LINES] = &linesCallBacks; + return b; +} diff --git a/app/wlib/mswlib/mswlist.c b/app/wlib/mswlib/mswlist.c new file mode 100644 index 0000000..968624a --- /dev/null +++ b/app/wlib/mswlib/mswlist.c @@ -0,0 +1,1173 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * List Boxes + * + ***************************************************************************** + */ + +static XWNDPROC oldListProc = NULL; +static XWNDPROC newListProc; +static XWNDPROC oldComboProc = NULL; +static XWNDPROC newComboProc; + +struct wList_t { + WOBJ_COMMON + int count; + int last; + long * valueP; + wListCallBack_p action; + wBool_t editable; + int colCnt; + wPos_t * colWidths; + wBool_t * colRightJust; + const char * * colTitles; + wPos_t maxWidth; + wPos_t scrollPos; + HWND hScrollWnd; + wPos_t scrollH; + wPos_t dragPos; + int dragCol; + wPos_t dragColWidth; + }; + + +typedef struct { + void * itemContext; + wIcon_p bm; + wBool_t selected; + } listData; + +static int LIST_HEIGHT = 19; +static int listTitleHeight = 16; + + +void wListClear( + wList_p b ) +{ + UINT msg; + if (b->type==B_LIST) + msg = LB_RESETCONTENT; + else + msg = CB_RESETCONTENT; + SendMessage( b->hWnd, msg, 0, 0 ); + b->last = -1; + b->count = 0; +} + + + +void wListSetSize( wList_p bl, wPos_t w, wPos_t h ) +{ + int rc; + RECT rect; + wPos_t y; + + bl->w = w; + bl->h = h; + y = bl->y; + if ( bl->hScrollWnd && bl->maxWidth > bl->w ) + h -= bl->scrollH; + if ( bl->colTitles ) { + h -= listTitleHeight; + y += listTitleHeight; + } + rc = SetWindowPos( bl->hWnd, HWND_TOP, 0, 0, + w, h, SWP_NOMOVE|SWP_NOZORDER); + if ( bl->hScrollWnd ) { + if ( bl->maxWidth > bl->w ) { + GetClientRect( bl->hWnd, &rect ); + rc = SetWindowPos( bl->hScrollWnd, HWND_TOP, bl->x, y+rect.bottom+2, + bl->w, bl->scrollH, SWP_NOZORDER); + ShowWindow( bl->hScrollWnd, SW_SHOW ); + } else { + ShowWindow( bl->hScrollWnd, SW_HIDE ); + } + } + +} + + +void wListSetIndex( + wList_p bl, + int index ) +{ + listData * ldp; + + wListGetCount(bl); + if ( index >= bl->count ) + index = bl->count-1; + if ( bl->last == index && index == -1 ) + return; + if ( bl->type==B_LIST && (bl->option&BL_MANY) != 0 ) { + if ( bl->last != -1 ) + SendMessage( bl->hWnd, LB_SETSEL, 0, MAKELPARAM(bl->last,0) ); + if ( index >= 0 ) + SendMessage( bl->hWnd, LB_SETSEL, 1, MAKELPARAM(index, 0) ); + } else { + SendMessage( bl->hWnd, + bl->type==B_LIST?LB_SETCURSEL:CB_SETCURSEL, index, 0 ); + } + if ( bl->last >= 0 ) { + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + bl->last, 0L ); + if ( ldp && ldp!=(void*)LB_ERR ) + ldp->selected = FALSE; + } + if ( index >= 0 ) { + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + index, 0L ); + if ( ldp && ldp!=(void*)LB_ERR ) + ldp->selected = TRUE; + } + /*if (b->option&BL_ICON)*/ + InvalidateRect( bl->hWnd, NULL, FALSE ); + bl->last = index; +} + + +wIndex_t wListGetIndex( + wList_p b ) +{ + return b->last; +} + + +void wListSetActive( + wList_p b, + int inx, + wBool_t active ) +{ +} + + +void wListSetEditable( + wList_p b, + wBool_t editable ) +{ + b->editable = editable; +} + + +void wListSetValue( + wList_p bl, + const char * val ) +{ + if ( bl->type == B_DROPLIST ) { + SendMessage( bl->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)val ); + bl->last = -1; + } +} + + +wIndex_t wListFindValue( + wList_p bl, + const char * val ) +{ + wIndex_t inx; + WORD cnt; + wListGetCount(bl); + for ( inx = 0; inx < bl->count ; inx++ ) { + cnt = (int)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETTEXT:CB_GETLBTEXT), inx, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if ( strcmp( val, mswTmpBuff ) == 0 ) + return inx; + } + return -1; +} + + +wIndex_t wListGetValues( + wList_p bl, + char * s, + int siz, + void * * listContextRef, + void * * itemContextRef ) +{ + WORD cnt; + WORD msg; + WORD inx = bl->last; + listData *ldp = NULL; + if ( bl->type==B_DROPLIST && bl->last < 0 ) { + msg = WM_GETTEXT; + inx = sizeof mswTmpBuff; + } else { + if ( bl->last < 0 ) + goto EMPTY; + if ( bl->type==B_LIST ) { + msg = LB_GETTEXT; + } else { + msg = CB_GETLBTEXT; + } + } + cnt = (int)SendMessage( bl->hWnd, msg, inx, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (s) + strncpy( s, mswTmpBuff, siz ); + if (bl->last >= 0) { + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + bl->last, 0L ); + if ( ldp==(listData*)LB_ERR ) + ldp = NULL; + } else { + ldp = NULL; + } +EMPTY: + if (itemContextRef) + *itemContextRef = (ldp?ldp->itemContext:NULL); + if (listContextRef) + *listContextRef = bl->data; + return bl->last; +} + +wBool_t wListSetValues( + wList_p b, + wIndex_t inx, + const char * labelStr, + wIcon_p bm, + void * itemData ) +{ + listData * ldp; + WORD curSel; + ldp = (listData*)malloc( sizeof *ldp ); + ldp->itemContext = itemData; + ldp->bm = bm; + ldp->selected = FALSE; + if ( (b->option&BL_MANY) == 0 ) + curSel = (WORD)SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_GETCURSEL:CB_GETCURSEL, + (WPARAM)0, + (DWORD)0L ); + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_DELETESTRING:CB_DELETESTRING, + (WPARAM)inx, + (DWORD)0L ); + inx = (wIndex_t)SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_INSERTSTRING:CB_INSERTSTRING, + (WPARAM)inx, + (DWORD)(LPSTR)labelStr ); + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETITEMDATA:CB_SETITEMDATA, + (WPARAM)inx, + (DWORD)ldp ); + if ( (b->option&BL_MANY) == 0 && curSel == (WORD)inx) + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETCURSEL:CB_SETCURSEL, + (WPARAM)inx, + (DWORD)0L ); + /*if (b->option&BL_ICON)*/ + InvalidateRect( b->hWnd, NULL, FALSE ); + return TRUE; +} + + +void wListDelete( + wList_p b, + wIndex_t inx ) +{ + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_DELETESTRING:CB_DELETESTRING, + (WPARAM)inx, + (DWORD)0L ); +} + + +wIndex_t wListGetCount( + wList_p bl ) +{ + bl->count = (int)SendMessage( bl->hWnd, (UINT)bl->type==B_LIST?LB_GETCOUNT:CB_GETCOUNT, 0, 0L ); + return bl->count; +} + + +void * wListGetItemContext( + wList_p bl, + wIndex_t inx ) +{ + listData * ldp; + wListGetCount(bl); + if ( inx < 0 || inx >= bl->count ) return NULL; + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + inx, 0L ); + return ((ldp&&ldp!=(void*)LB_ERR)?ldp->itemContext:NULL); +} + + +wBool_t wListGetItemSelected( + wList_p bl, + wIndex_t inx ) +{ + listData * ldp; + wListGetCount(bl); + if ( inx < 0 || inx >= bl->count ) return FALSE; + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + inx, 0L ); + return ((ldp&&ldp!=(void*)LB_ERR)?ldp->selected:FALSE); +} + + +wIndex_t wListGetSelectedCount( + wList_p bl ) +{ + wIndex_t selcnt, inx; + wListGetCount(bl); + for ( selcnt=inx=0; inx<bl->count; inx++ ) + if ( wListGetItemSelected( bl, inx ) ) + selcnt++; + return selcnt; +} + + +wIndex_t wListAddValue( + wList_p b, + const char * value, + wIcon_p bm, + void * itemContext ) +{ + int nindex; + listData * ldp; + ldp = (listData*)malloc( sizeof *ldp ); + ldp->itemContext = itemContext; + ldp->bm = bm; + ldp->selected = FALSE; + if ( value == NULL ) + value = ""; + b->count++; + nindex = (int)SendMessage( + b->hWnd, + (UINT)b->type==B_LIST?LB_ADDSTRING:CB_ADDSTRING, + (WPARAM)0, + (DWORD)value ); + if (nindex == 0) { + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETCURSEL:CB_SETCURSEL, + (WPARAM)nindex, + (DWORD)0 ); + b->last = 0; + } + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETITEMDATA:CB_SETITEMDATA, + (WPARAM)nindex, + (DWORD)ldp ); + return nindex; +} + + +int wListGetColumnWidths( + wList_p bl, + int colCnt, + wPos_t * colWidths ) +{ + wIndex_t inx; + + if ( bl->type != B_LIST ) + return 0; + if ( bl->colWidths == NULL ) + return 0; + for ( inx=0; inx<colCnt; inx++ ) { + if ( inx < bl->colCnt ) + colWidths[inx] = bl->colWidths[inx]; + else + colWidths[inx] = 0; + } + return bl->colCnt; +} + + +static void listSetBusy( + wControl_p b, + BOOL_T busy) +{ + wList_p bl = (wList_p)b; + + EnableWindow( bl->hWnd, !(BOOL)busy ); + if ( bl->hScrollWnd ) + EnableWindow( bl->hScrollWnd, !(BOOL)busy ); +} + +static void listShow( + wControl_p b, + BOOL_T show) +{ + wList_p bl = (wList_p)b; + + ShowWindow( bl->hWnd, show?SW_SHOW:SW_HIDE ); + if ( bl->hScrollWnd && bl->maxWidth > bl->w ) + ShowWindow( bl->hScrollWnd, show?SW_SHOW:SW_HIDE ); +#ifdef SHOW_DOES_SETFOCUS + if ( show && (bl->option&BO_READONLY)==0 ) + hWnd = SetFocus( bl->hWnd ); +#endif +} + +static void listSetPos( + wControl_p b, + wPos_t x, + wPos_t y ) +{ + wList_p bl = (wList_p)b; + wPos_t x1, y1; + RECT rect; + + bl->x = x1 = x; + bl->y = y1 = y; + if ( bl->colTitles ) + y1 += listTitleHeight; + if (!SetWindowPos( b->hWnd, HWND_TOP, x1, y1, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("listSetPos"); + if ( bl->hScrollWnd && bl->maxWidth > bl->w ) { + GetClientRect( bl->hWnd, &rect ); + if (!SetWindowPos( bl->hScrollWnd, HWND_TOP, x1, y1+rect.bottom+2, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("listSetPos2"); + } +} + + +static void listRepaintLabel( + HWND hWnd, + wControl_p b ) +{ + wList_p bl = (wList_p)b; + HDC hDc; + RECT rc; + HFONT hFont; + HPEN hPen0, hPen1, hPen2, hPen3; + HBRUSH hBrush; + const char * * title; + int inx; + int start; + wPos_t colWidth; + + mswRepaintLabel( hWnd, b ); + if ( bl->colTitles == NULL ) + return; + hDc = GetDC( hWnd ); + start = bl->x-bl->scrollPos+2; + rc.top = bl->y; + rc.bottom = bl->y+listTitleHeight; + rc.left = bl->x-1; + rc.right = bl->x+bl->w; + hBrush = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) ); + FillRect( hDc, &rc, hBrush ); + SetBkColor( hDc, GetSysColor( COLOR_BTNFACE ) ); + + hFont = SelectObject( hDc, mswLabelFont ); + hPen1 = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_BTNTEXT ) ); + hPen2 = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_BTNHIGHLIGHT ) ); + hPen3 = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_BTNSHADOW ) ); + hPen0 = SelectObject( hDc, hPen1 ); + MoveTo( hDc, rc.left, rc.top ); + LineTo( hDc, rc.right, rc.top ); + LineTo( hDc, rc.right, rc.bottom ); + LineTo( hDc, rc.left, rc.bottom ); + LineTo( hDc, rc.left, rc.top ); + SelectObject( hDc, hPen2 ); + MoveTo( hDc, rc.left+1, rc.bottom-1 ); + LineTo( hDc, rc.left+1, rc.top+1 ); + LineTo( hDc, rc.right-1, rc.top+1 ); + SelectObject( hDc, hPen3 ); + MoveTo( hDc, rc.left+2, rc.bottom-1 ); + LineTo( hDc, rc.right-1, rc.bottom-1 ); + LineTo( hDc, rc.right-1, rc.top+1 ); + rc.top += 2; + rc.bottom -= 1; + for ( inx=0,title=bl->colTitles; inx<bl->colCnt&&*title&&start<bl->x+bl->w; inx++ ) { + colWidth = bl->colWidths[inx]; + if ( start+colWidth >= 3 ) { + rc.left = start; + if ( rc.left < bl->x+2 ) + rc.left = bl->x+2; + rc.right = start+colWidth; + if ( rc.right > bl->x+bl->w-1 ) + rc.right = bl->x+bl->w-1; + ExtTextOut( hDc, start+1, rc.top+0, + ETO_CLIPPED|ETO_OPAQUE, &rc, + *title, strlen(*title), NULL ); + if ( start-bl->x >= 3 ) { + SelectObject( hDc, hPen1 ); + MoveTo( hDc, start-1, rc.top-1 ); + LineTo( hDc, start-1, rc.bottom+3 ); + SelectObject( hDc, hPen2 ); + MoveTo( hDc, start, rc.top ); + LineTo( hDc, start, rc.bottom+1 ); + SelectObject( hDc, hPen3 ); + MoveTo( hDc, start-2, rc.top ); + LineTo( hDc, start-2, rc.bottom+1 ); + } + } + title++; + start += colWidth; + } + SelectObject( hDc, hPen0 ); + SelectObject( hDc, hFont ); + DeleteObject( hBrush ); + DeleteObject( hPen1 ); + DeleteObject( hPen2 ); + DeleteObject( hPen3 ); +} + + +#ifdef LATER +static void listHandleSelectionState( LPDRAWITEMSTRUCT lpdis, LPRECT rc ) +{ + int oldROP; + oldROP = SetROP2( lpdis->hDC, R2_NOT ); + Rectangle( lpdis->hDC, rc->left, rc->top, rc->right, rc->bottom ); + SetROP2( lpdis->hDC, oldROP ); + /*InvertRect( lpdis->hDC, rc );*/ +} +#endif + +static void listHandleFocusState( LPDRAWITEMSTRUCT lpdis, LPRECT rc ) +{ + DrawFocusRect( lpdis->hDC, rc ); +} + + +LRESULT listProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wList_p bl = (wList_p)b; + int cnt, inx, selected; + long len; + listData * ldp; + HDC hDc; + LPMEASUREITEMSTRUCT lpmis; + TEXTMETRIC tm; + LPDRAWITEMSTRUCT lpdis; + RECT rc, rc1; + char * cp0, * cp1; + wPos_t colWidth, x; + int nPos; + HFONT hFont; + HPEN hPen; + HBRUSH hBrush; + WPARAM notification; + COLORREF col; + + if (bl) switch( message ) { + + case WM_COMMAND: + notification = WCMD_PARAM_NOTF; + switch (bl->type) { + case B_LIST: + switch (notification) { + case LBN_SELCHANGE: + case LBN_DBLCLK: + if ( (bl->option&BL_DBLCLICK)!=0 ? + notification!=LBN_DBLCLK : + notification==LBN_DBLCLK ) + break; + if ( (bl->option&BL_MANY) ) { + wListGetCount(bl); + for ( inx=0; inx<bl->count; inx++ ) { + ldp = (listData*)SendMessage( bl->hWnd, LB_GETITEMDATA, inx, 0L ); + if ( ldp != NULL && ldp != (void*)LB_ERR ) { + selected = ((long)SendMessage( bl->hWnd, LB_GETSEL, inx, 0L ) != 0L ); + if ( selected != ldp->selected ) { + ldp->selected = selected; + if ( selected ) { + bl->last = inx; + cnt = (int)SendMessage( bl->hWnd, LB_GETTEXT, bl->last, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + } else { + mswTmpBuff[0] = '\0'; + } + if ( bl->action ) + bl->action( inx, mswTmpBuff, selected?1:2, bl->data, ldp->itemContext ); + if ( selected && bl->valueP ) + *bl->valueP = bl->last; + } + } + } + } else { + bl->last = (int)SendMessage( bl->hWnd, LB_GETCURSEL, 0, 0L ); + cnt = (int)SendMessage( bl->hWnd, LB_GETTEXT, bl->last, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (bl->action) { + ldp = (listData*)SendMessage( bl->hWnd, LB_GETITEMDATA, + bl->last, 0L ); + bl->action( bl->last, mswTmpBuff, 1, bl->data, + ((bl->last>=0&&ldp&&ldp!=(void*)LB_ERR)?ldp->itemContext:NULL) ); + } + if (bl->valueP) { + *bl->valueP = bl->last; + } + } + break; + + case LBN_KILLFOCUS: + if ( ( bl->option&BL_MANY ) == 0 && + bl->last != (int)SendMessage( bl->hWnd, LB_GETCURSEL, 0, 0L ) ) + (void)SendMessage( bl->hWnd, LB_SETCURSEL, bl->last, 0L ); + break; + } + break; + + case B_DROPLIST: + case B_COMBOLIST: + switch (notification) { + case CBN_SELCHANGE: + case CBN_DBLCLK: + if ( (bl->type == B_DROPLIST) || + ( (bl->option&BL_DBLCLICK)!=0 ? + notification!=CBN_DBLCLK : + notification==CBN_DBLCLK) ) + break; + + case CBN_CLOSEUP: + bl->last = (int)SendMessage( bl->hWnd, CB_GETCURSEL, 0, 0L ); + if (bl->last < 0) + break; + if (bl->action) { + cnt = (int)SendMessage( bl->hWnd, CB_GETLBTEXT, bl->last, + (DWORD)(LPSTR)mswTmpBuff ); + ldp = (listData*)SendMessage( bl->hWnd, CB_GETITEMDATA, + bl->last, 0L ); + mswTmpBuff[cnt] = '\0'; + bl->action( bl->last, mswTmpBuff, 1, bl->data, + ((bl->last>=0&&ldp&&ldp!=(void*)LB_ERR)?ldp->itemContext:NULL) ); + } + if (bl->valueP) { + *bl->valueP = bl->last; + } + mswAllowBalloonHelp = TRUE; + /*SendMessage( bl->bWnd, CB_SETCURSEL, bl->last, 0L );*/ + break; + + case CBN_KILLFOCUS: + inx = (int)SendMessage( bl->hWnd, CB_GETCURSEL, 0, 0L ); + if ( bl->last != inx ) + (void)SendMessage( bl->hWnd, CB_SETCURSEL, bl->last, 0L ); + break; + + case CBN_DROPDOWN: + mswAllowBalloonHelp = FALSE; + break; + + case CBN_EDITCHANGE: + bl->last = -1; + if (bl->action) { + cnt = (int)SendMessage( bl->hWnd, WM_GETTEXT, sizeof mswTmpBuff, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + bl->action( -1, mswTmpBuff, 1, bl->data, NULL ); + } + break; + } + break; + } + break; + + case WM_MEASUREITEM: + lpmis = (LPMEASUREITEMSTRUCT)lParam; + hDc = GetDC( hWnd ); + if ( bl->type == B_LIST ) + hFont = SelectObject( hDc, mswLabelFont ); + GetTextMetrics( hDc, &tm ); + lpmis->itemHeight = tm.tmHeight; + if ( bl->type == B_LIST ) + SelectObject( hDc, hFont ); + ReleaseDC( hWnd, hDc ); + break; + + case WM_DRAWITEM: + lpdis = (LPDRAWITEMSTRUCT)lParam; + if (lpdis->itemID == -1) { + listHandleFocusState(lpdis, &lpdis->rcItem); + return TRUE; + } + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + lpdis->itemID, 0L ); + rc = lpdis->rcItem; + if (lpdis->itemAction & (ODA_DRAWENTIRE|ODA_SELECT|ODA_FOCUS)) { + if( bl->type == B_LIST ) + hFont = SelectObject( lpdis->hDC, mswLabelFont ); + cnt = (int)SendMessage( lpdis->hwndItem, + (bl->type==B_LIST?LB_GETTEXT:CB_GETLBTEXT), + lpdis->itemID, (LONG)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if ( lpdis->itemState & ODS_SELECTED ) { + SetTextColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHTTEXT ) ); + SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); + } else { + SetTextColor( lpdis->hDC, GetSysColor( COLOR_WINDOWTEXT ) ); + SetBkColor( lpdis->hDC, GetSysColor( COLOR_WINDOW ) ); + } + rc1 = rc; + rc1.left -= bl->scrollPos; + for ( inx=0,cp0=mswTmpBuff; inx<bl->colCnt&&cp0&&rc1.left<rc.right; inx++ ) { + if ( inx>=bl->colCnt-1 || (cp1=strchr(cp0,'\t')) == NULL ) { + len = strlen( cp0 ); + cp1=cp0 + len; // JBB, to avoid an MSC error below where cp1 has not been defined. + } else { + len = cp1-cp0; + cp1 ++; + } + if ( bl->colWidths ) { + colWidth = bl->colWidths[inx]; + } else { + colWidth = rc.right; + } + if ( inx == 0 && ldp && ldp!=(void*)LB_ERR && ldp->bm ) { + if (mswPalette) { + SelectPalette( lpdis->hDC, mswPalette, 0 ); + cnt = RealizePalette( lpdis->hDC ); + } + hPen = SelectObject( lpdis->hDC, CreatePen( PS_SOLID, 0, GetSysColor( COLOR_WINDOW ) ) ); + hBrush = SelectObject( lpdis->hDC, CreateSolidBrush( GetSysColor( COLOR_WINDOW ) ) ); + Rectangle( lpdis->hDC, rc1.left, rc1.top, rc1.right, rc1.bottom ); + DeleteObject( SelectObject( lpdis->hDC, hPen ) ); + DeleteObject( SelectObject( lpdis->hDC, hBrush ) ); + + col = RGB( (ldp->bm->colormap[ 1 ]).rgbRed, + (ldp->bm->colormap[ 1 ]).rgbGreen, + (ldp->bm->colormap[ 1 ]).rgbBlue ); + mswDrawIcon( lpdis->hDC, rc1.left+2, rc.top+0, ldp->bm, 0, col, col); + + rc1.left += ldp->bm->w+6; + colWidth -= ldp->bm->w+6; + } + if ( inx>=bl->colCnt-1 || (rc1.right = rc1.left + colWidth) > rc.right ) + rc1.right = rc.right; + if ( rc1.right > 0 && rc1.left+3 < rc.right ) { + ExtTextOut( lpdis->hDC, rc1.left+3, rc1.top+1, + ETO_CLIPPED | ETO_OPAQUE, &rc1, + (LPSTR)cp0, (int)len, NULL ); + } + rc1.left = rc1.right; + cp0 = cp1; + } + if ( lpdis->itemState & ODS_SELECTED ) { + SetTextColor( lpdis->hDC, GetSysColor( COLOR_WINDOWTEXT ) ); + SetBkColor( lpdis->hDC, GetSysColor( COLOR_WINDOW ) ); + } + if (lpdis->itemState & ODS_FOCUS) { + DrawFocusRect( lpdis->hDC, &rc ); + } + if ( bl->type == B_LIST) + SelectObject( lpdis->hDC, hFont ); + return TRUE; + } + + break; + + case WM_HSCROLL: + len = ((long)bl->maxWidth)-((long)bl->w); + if ( len <= 0 ) + return 0; + switch ( WSCROLL_PARAM_CODE ) { + case SB_LEFT: + if ( bl->scrollPos == 0 ) + return 0; + bl->scrollPos = 0; + break; + case SB_LINELEFT: + case SB_PAGELEFT: + if ( bl->scrollPos == 0 ) + return 0; + for ( inx=colWidth=0; inx<bl->colCnt; inx++ ) { + if ( colWidth+bl->colWidths[inx] >= bl->scrollPos ) { + bl->scrollPos = colWidth; + break; + } + colWidth += bl->colWidths[inx]; + } + break; + case SB_LINERIGHT: + case SB_PAGERIGHT: + if ( bl->scrollPos >= len ) + return 0; + for ( inx=colWidth=0; inx<bl->colCnt; inx++ ) { + if ( colWidth >= bl->scrollPos ) { + bl->scrollPos = colWidth+bl->colWidths[inx]; + break; + } + colWidth += bl->colWidths[inx]; + } + break; + case SB_RIGHT: + if ( bl->scrollPos >= len ) + return 0; + bl->scrollPos = (int)len; + break; + case SB_THUMBTRACK: + return 0; + case SB_THUMBPOSITION: + nPos = (int)WSCROLL_PARAM_NPOS; + bl->scrollPos = (int)(len*nPos/100); + break; + case SB_ENDSCROLL: + return 0; + } + if ( bl->scrollPos > len ) bl->scrollPos = (int)len; + if ( bl->scrollPos < 0 ) bl->scrollPos = 0; + nPos = (int)(((long)bl->scrollPos)*100L/len+0.5); + SetScrollPos( bl->hScrollWnd, SB_CTL, nPos, TRUE ); + InvalidateRect( bl->hWnd, NULL, FALSE ); + listRepaintLabel( ((wControl_p)(bl->parent))->hWnd, (wControl_p)bl ); + return 0; + + case WM_LBUTTONDOWN: + if ( bl->type != B_LIST ) + break; + if ( bl->colCnt <= 1 ) + break; + x = bl->dragPos = LOWORD(lParam)+bl->scrollPos-4; + bl->dragCol = -1; + for ( inx=0; inx<bl->colCnt; inx++ ) { + x -= bl->colWidths[inx]; + if ( x < -5 ) break; + if ( x <= 0 ) { bl->dragCol = inx; break; } + if ( x > bl->colWidths[inx+1] ) continue; + if ( x <= 10 ) { bl->dragCol = inx; break; } + } + if ( bl->dragCol >= 0 ) + bl->dragColWidth = bl->colWidths[inx]; + return 0L; + +#ifdef LATER + case WM_MOUSEMOVE: + if ( (wParam&MK_LBUTTON) == 0 ) + break; + if ( bl->type != B_LIST ) + break; + if ( bl->colCnt <= 1 ) + break; + x = LOWORD(lParam)+bl->scrolPos; + for ( inx=0; inx<bl->colCnt; inx++ ) { + x -= bl->colWidths[inx]; + if ( x <= 0 ) + break; + } + return 0L; +#endif + + case WM_MOUSEMOVE: + if ( (wParam&MK_LBUTTON) == 0 ) + break; + case WM_LBUTTONUP: + if ( bl->type != B_LIST ) + break; + if ( bl->colCnt <= 1 ) + break; + if ( bl->dragCol < 0 ) + break; + x = LOWORD(lParam)+bl->scrollPos-4-bl->dragPos; /* WIN32??? */ + bl->colWidths[bl->dragCol] = bl->dragColWidth+x; + if ( bl->colWidths[bl->dragCol] < 0 ) + bl->colWidths[bl->dragCol] = 0; + for ( bl->maxWidth=inx=0; inx<bl->colCnt; inx++ ) + bl->maxWidth += bl->colWidths[inx]; + if ( bl->maxWidth <= bl->w ) { + x = bl->w - bl->maxWidth; + bl->colWidths[bl->colCnt-1] += x; + bl->maxWidth = bl->w; + bl->scrollPos = 0; + } else { + if ( bl->scrollPos+bl->w > bl->maxWidth ) { + bl->scrollPos = bl->maxWidth - bl->w; + } + } + InvalidateRect( bl->hWnd, NULL, FALSE ); + listRepaintLabel( ((wControl_p)(bl->parent))->hWnd, (wControl_p)bl ); + return 0L; + + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + +long FAR PASCAL _export pushList( + HWND hWnd, + UINT message, + 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 ); + + switch (message) { + case WM_CHAR: + if ( b != NULL) { + switch( WCMD_PARAM_ID ) { + 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; + } + return CallWindowProc( oldListProc, hWnd, message, wParam, lParam ); +} + +long FAR PASCAL _export pushCombo( + HWND hWnd, + UINT message, + 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 ); + + switch (message) { + case WM_CHAR: + if ( b != NULL) { + switch( WCMD_PARAM_ID ) { + 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; + } + return CallWindowProc( oldComboProc, hWnd, message, wParam, lParam ); +} + +static callBacks_t listCallBacks = { + listRepaintLabel, + NULL, + listProc, + listSetBusy, + listShow, + listSetPos }; + + +static wList_p listCreate( + int typ, + const char *className, + long style, + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + long *valueP, + wListCallBack_p action, + void *data, + wBool_t addFocus, + int *indexR ) +{ + wList_p b; + RECT rect; + int index; + + b = (wList_p)mswAlloc( parent, typ, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->count = 0; + b->last = -1; + b->valueP = valueP; + b->labelY += 4; + b->action = action; + b->maxWidth = 0; + b->scrollPos = 0; + b->scrollH = 0; + b->dragPos = 0; + b->dragCol = -1; + + b->hWnd = CreateWindow( className, NULL, + style | WS_CHILD | WS_VISIBLE | mswGetBaseStyle(parent), b->x, b->y, + width, LIST_HEIGHT*(int)number, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(LIST)"); + return b; + } + +#ifdef CONTROL3D + Ctl3dSubclassCtl( b->hWnd ); +#endif + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + b->colCnt = 1; + b->colWidths = NULL; + b->colTitles = NULL; + + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[typ] = &listCallBacks; + if (addFocus) { + mswChainFocus( (wControl_p)b ); + if (b->type == B_LIST) { + newListProc = MakeProcInstance( (XWNDPROC)pushList, mswHInst ); + oldListProc = (XWNDPROC)GetWindowLong( b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newListProc ); + } else { + newComboProc = MakeProcInstance( (XWNDPROC)pushCombo, mswHInst ); + oldComboProc = (XWNDPROC)GetWindowLong( b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newComboProc ); + } + } + if ( indexR ) + *indexR = index; + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + return b; +} + + +wList_p wListCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + int colCnt, + wPos_t * colWidths, + wBool_t * colRightJust, + const char * * colTitles, + long *valueP, + wListCallBack_p action, + void *data ) +{ + long bs; + wList_p bl; + static int dbu = 0; + RECT rect; + int index; + int i; + + bs = LBS_NOTIFY | WS_VSCROLL | WS_BORDER | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS; + if (option & BL_MANY) + bs |= LBS_MULTIPLESEL|LBS_EXTENDEDSEL; + if (option & BL_SORT) + bs |= LBS_SORT; + if ( colCnt > 1 ) + bs |= WS_HSCROLL; + if ( colTitles ) { + y += listTitleHeight; + number -= 1; + } + bl = listCreate( B_LIST, "LISTBOX", bs, parent, x, y, helpStr, + labelStr, option, number, width, valueP, action, data, TRUE, &index ); + if ( colTitles ) { + bl->y -= listTitleHeight; + bl->h += listTitleHeight; + } + if ( colCnt > 1 ) { + bl->colCnt = colCnt; + bl->colWidths = (int*)malloc( colCnt * sizeof *bl->colWidths ); + bl->colRightJust = (wBool_t*)malloc( colCnt * sizeof *bl->colRightJust ); + bl->colTitles = colTitles; + bl->maxWidth = 0; + memcpy( bl->colWidths, colWidths, colCnt * sizeof *bl->colWidths ); + for ( i=0; i<colCnt; i++ ) { + bl->colWidths[i] = colWidths[i]; + bl->maxWidth += bl->colWidths[i]; + } + bl->hScrollWnd = CreateWindow( "ScrollBar", NULL, + SBS_HORZ | SBS_BOTTOMALIGN | WS_CHILD | WS_VISIBLE | mswGetBaseStyle(parent), bl->x, bl->y, + width, CW_USEDEFAULT, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (bl->hScrollWnd == NULL) + mswFail("CreateWindow(LISTSCROLL)"); + SetScrollRange( bl->hScrollWnd, SB_CTL, 0, 100, TRUE ); + GetWindowRect( bl->hScrollWnd, &rect ); + bl->scrollH = rect.bottom - rect.top+2; + } + return bl; +} + + +wList_p wDropListCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + long *valueP, + wListCallBack_p action, + void *data ) +{ + long bs; + + if ( (option&BL_EDITABLE) != 0 ) + bs = CBS_DROPDOWN; + else + bs = CBS_DROPDOWNLIST; + bs |= WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS; + if (option & BL_SORT) + bs |= CBS_SORT; + return listCreate( B_DROPLIST, "COMBOBOX", bs, parent, x, y, helpStr, + labelStr, option, number, width, valueP, action, data, TRUE, NULL ); +} + +wList_p wComboListCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + long *valueP, + wListCallBack_p action, + void *data ) +{ + long bs; + + bs = CBS_SIMPLE | WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS; + if (option & BL_SORT) + bs |= CBS_SORT; + return listCreate( B_COMBOLIST, "COMBOBOX", bs, parent, x, y, helpStr, + labelStr, option, number, width, valueP, action, data, FALSE, NULL ); +} diff --git a/app/wlib/mswlib/mswmenu.c b/app/wlib/mswlib/mswmenu.c new file mode 100644 index 0000000..15053a2 --- /dev/null +++ b/app/wlib/mswlib/mswmenu.c @@ -0,0 +1,1062 @@ +#define OEMRESOURCE + +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <ctype.h> +#include <assert.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Menus + * + ***************************************************************************** + */ + +typedef enum { M_MENU, M_SEPARATOR, M_PUSH, M_LIST, M_LISTITEM, M_TOGGLE, M_RADIO } mtype_e; +typedef enum { MM_BUTT, MM_MENU, MM_BAR, MM_POPUP } mmtype_e; + +typedef struct wMenuItem_t * wMenuItem_p; + +struct radioButtonGroup { + int firstButton; /* id of first button in group */ + int lastButton; /* id of last button in group */ +}; + +/* NOTE: first field must be the same as WOBJ_COMMON */ +#define MOBJ_COMMON \ + WOBJ_COMMON \ + int index; \ + mtype_e mtype; \ + wMenu_p parentMenu; \ + wMenuItem_p mnext; + +struct wMenuItem_t { + MOBJ_COMMON + }; + +struct wMenu_t { + MOBJ_COMMON + mmtype_e mmtype; + wMenuItem_p first, last; + struct radioButtonGroup *radioGroup; + HMENU menu; + wButton_p button; + wMenuTraceCallBack_p traceFunc; + void * traceData; + }; + +struct wMenuPush_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuCallBack_p action; + long acclKey; + wBool_t enabled; + }; + +struct wMenuRadio_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuCallBack_p action; + long acclKey; + wBool_t enabled; + }; +struct wMenuToggle_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuToggleCallBack_p action; + long acclKey; + wBool_t enabled; + }; + +typedef struct wMenuListItem_t * wMenuListItem_p; +struct wMenuList_t { + MOBJ_COMMON + wMenuListItem_p left, right; + wMenu_p mlparent; + int max; + int count; + wMenuListCallBack_p action; + }; + +struct wMenuListItem_t { + MOBJ_COMMON + wMenuListItem_p left, right; + wMenuListCallBack_p action; + }; + +#define UNCHECK (0) +#define CHECK (1) +#define RADIOCHECK (2) +#define RADIOUNCHECK (3) + +static HBITMAP checked; +static HBITMAP unchecked; +static HBITMAP checkedRadio; +static HBITMAP uncheckedRadio; + + +/* + ***************************************************************************** + * + * Internal Functions + * + ***************************************************************************** + */ + +char * mswStrdup( const char * str ) +{ + char * ret; + if (str) { + ret = (char*)malloc( strlen(str)+1 ); + strcpy( ret, str ); + } else + ret = NULL; + return ret; +} + +static LRESULT menuPush( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wMenuItem_p m = (wMenuItem_p)b; + wBool_t set; + + mswAllowBalloonHelp = TRUE; + + switch( message ) { + + case WM_COMMAND: + + switch (m->mtype) { + default: + mswFail( "pushMenu" ); + break; + case M_PUSH: + if (((wMenuPush_p)m)->action) + ((wMenuPush_p)m)->action(((wMenuPush_p)m)->data); + break; + case M_TOGGLE: + set = wMenuToggleGet((wMenuToggle_p)m); + set = !set; + wMenuToggleSet((wMenuToggle_p)m,set); + if (((wMenuToggle_p)m)->action) + ((wMenuToggle_p)m)->action(set, ((wMenuPush_p)m)->data); + break; + case M_LISTITEM: + if (((wMenuListItem_p)m)->action) + ((wMenuListItem_p)m)->action(0, "", ((wMenuListItem_p)m)->data); + break; + case M_RADIO: + if (((wMenuRadio_p)m)->action) + ((wMenuRadio_p)m)->action(((wMenuRadio_p)m)->data); + break; + } + return 0L; + } + if ( (m->parentMenu)->traceFunc ) { + (m->parentMenu)->traceFunc( m->parentMenu, m->labelStr, ((wMenu_p)m->parentMenu)->traceData ); + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + +static void menuDone( wControl_p b ) +{ + wMenuItem_p m = (wMenuItem_p)b; + switch ( m->mtype ) { + case M_MENU: + if ( ((wMenu_p)m)->mmtype == MM_BUTT || + ((wMenu_p)m)->mmtype == MM_POPUP ) + DestroyMenu( ((wMenu_p)m)->menu ); + break; + } +} + +static callBacks_t menuItemCallBacks = { + NULL, + menuDone, + menuPush }; + + +static wMenuItem_p createMenuItem( + wMenu_p m, + mtype_e mtype, + const char * helpStr, + const char * labelStr, + int size ) +{ + wMenuItem_p mi; + + mi = (wMenuItem_p)calloc( 1, size ); + mi->type = B_MENUITEM; + /*mi->messageProc = menuPush;*/ + mi->index = mswRegister( (wControl_p)mi ); + mi->mtype = mtype; + if (m) { + if (m->last != NULL) { + m->last->mnext = mi; + } else { + m->first = m->last = mi; + } + m->last = mi; + } + mi->mnext = NULL; + mi->labelStr = mswStrdup( labelStr ); +// if (helpStr != NULL) { +// char *string; +// string = malloc( strlen(helpStr) + 1 ); +// strcpy( string, helpStr ); +// /*xv_set(mi->menu_item, XV_HELP_DATA, string, 0 );*/ +// } + mswCallBacks[B_MENUITEM] = &menuItemCallBacks; + return mi; +} + +/* + ***************************************************************************** + * + * Accelerators + * + ***************************************************************************** + */ + + +typedef struct { + long acclKey; + wMenuPush_p mp; + wAccelKeyCallBack_p action; + wAccelKey_e key; + void * data; + } acclTable_t, *acclTable_p; +dynArr_t acclTable_da; +#define acclTable(N) DYNARR_N( acclTable_t, acclTable_da, N ) + + +int mswMenuAccelerator( + wWin_p win, + long acclKey ) +{ + acclTable_p at; + if ( ((wControl_p)win)->type != W_MAIN && + ((wControl_p)win)->type != W_POPUP ) + return 0; + for ( at = &acclTable(0); at<&acclTable(acclTable_da.cnt); at++ ) { + if (at->acclKey == acclKey) { + if (at->mp) { + if (at->mp->enabled && at->mp->action) + at->mp->action(at->mp->data); + return 1; + } else if (at->action) { + at->action( at->key, at->data ); + return 1; + } else { + return 0; + } + } + } + return 0; +} + + + +static long acclKeyMap[] = { + 0, /* wAccelKey_None, */ + VK_DELETE, /* wAccelKey_Del, */ + VK_INSERT, /* wAccelKey_Ins, */ + VK_HOME, /* wAccelKey_Home, */ + VK_END, /* wAccelKey_End, */ + VK_PRIOR, /* wAccelKey_Pgup, */ + VK_NEXT, /* wAccelKey_Pgdn, */ + VK_UP, /* wAccelKey_Up, */ + VK_DOWN, /* wAccelKey_Down, */ + VK_RIGHT, /* wAccelKey_Right, */ + VK_LEFT, /* wAccelKey_Left, */ + VK_BACK, /* wAccelKey_Back, */ + VK_F1, /* wAccelKey_F1, */ + VK_F2, /* wAccelKey_F2, */ + VK_F3, /* wAccelKey_F3, */ + VK_F4, /* wAccelKey_F4, */ + VK_F5, /* wAccelKey_F5, */ + VK_F6, /* wAccelKey_F6, */ + VK_F7, /* wAccelKey_F7, */ + VK_F8, /* wAccelKey_F8, */ + VK_F9, /* wAccelKey_F9, */ + VK_F10, /* wAccelKey_F10, */ + VK_F11, /* wAccelKey_F11, */ + VK_F12 /* wAccelKey_F12, */ + }; + + +void wAttachAccelKey( + wAccelKey_e key, + int modifier, + wAccelKeyCallBack_p action, + void * data ) +{ + acclTable_t * ad; + if ( key < 1 || key > wAccelKey_F12 ) { + mswFail( "wAttachAccelKey: key out of range" ); + return; + } + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + ad = &acclTable(acclTable_da.cnt-1); + ad->acclKey = acclKeyMap[key] | (modifier<<8); + ad->key = key; + ad->action = action; + ad->data = data; + ad->mp = NULL; +} + +/* + ***************************************************************************** + * + * Menu Item Create + * + ***************************************************************************** + */ + +HBITMAP GetMyCheckBitmaps(UINT fuCheck) +{ + COLORREF crBackground; /* background color */ + HBRUSH hbrBackground; /* background brush */ + HBRUSH hbrTargetOld; /* original background brush */ + HDC hdcSource; /* source device context */ + HDC hdcTarget; /* target device context */ + HBITMAP hbmpCheckboxes; /* handle to check-box bitmap */ + BITMAP bmCheckbox; /* structure for bitmap data */ + HBITMAP hbmpSourceOld; /* handle to original source bitmap */ + HBITMAP hbmpTargetOld; /* handle to original target bitmap */ + HBITMAP hbmpCheck; /* handle to check-mark bitmap */ + RECT rc; /* rectangle for check-box bitmap */ + WORD wBitmapX; /* width of check-mark bitmap */ + WORD wBitmapY; /* height of check-mark bitmap */ + + /* Get the menu background color and create a solid brush + with that color. */ + + crBackground = GetSysColor(COLOR_MENU); + hbrBackground = CreateSolidBrush(crBackground); + + /* Create memory device contexts for the source and + destination bitmaps. */ + + hdcSource = CreateCompatibleDC((HDC) NULL); + hdcTarget = CreateCompatibleDC(hdcSource); + + /* Get the size of the system default check-mark bitmap and + create a compatible bitmap of the same size. */ + + wBitmapX = GetSystemMetrics(SM_CXMENUCHECK); + wBitmapY = GetSystemMetrics(SM_CYMENUCHECK); + + hbmpCheck = CreateCompatibleBitmap(hdcSource, wBitmapX, + wBitmapY); + + /* Select the background brush and bitmap into the target DC. */ + + hbrTargetOld = SelectObject(hdcTarget, hbrBackground); + hbmpTargetOld = SelectObject(hdcTarget, hbmpCheck); + + /* Use the selected brush to initialize the background color + of the bitmap in the target device context. */ + + PatBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, PATCOPY); + + /* Load the predefined check box bitmaps and select it + into the source DC. */ + + hbmpCheckboxes = LoadBitmap((HINSTANCE) NULL, + (LPTSTR) OBM_CHECKBOXES); + + hbmpSourceOld = SelectObject(hdcSource, hbmpCheckboxes); + + /* Fill a BITMAP structure with information about the + check box bitmaps, and then find the upper-left corner of + the unchecked check box or the checked check box. */ + + GetObject(hbmpCheckboxes, sizeof(BITMAP), &bmCheckbox); + + switch( fuCheck ) { + + case UNCHECK: + rc.left = 0; + rc.right = (bmCheckbox.bmWidth / 4); + rc.top = 0; + rc.bottom = (bmCheckbox.bmHeight / 3); + break; + case CHECK: + rc.left = (bmCheckbox.bmWidth / 4); + rc.right = (bmCheckbox.bmWidth / 4) * 2; + rc.top = 0; + rc.bottom = (bmCheckbox.bmHeight / 3); + break; + case RADIOCHECK: + rc.left = (bmCheckbox.bmWidth / 4); + rc.right = (bmCheckbox.bmWidth / 4) * 2; + rc.top = (bmCheckbox.bmHeight / 3) + 1; + rc.bottom = (bmCheckbox.bmHeight / 3) * 2; + break; + case RADIOUNCHECK: + rc.top = (bmCheckbox.bmHeight / 3) + 1; + rc.bottom = (bmCheckbox.bmHeight / 3) * 2; + rc.left = 0; + rc.right = (bmCheckbox.bmWidth / 4); + + break; + } + + /* Copy the appropriate bitmap into the target DC. If the + check-box bitmap is larger than the default check-mark + bitmap, use StretchBlt to make it fit; otherwise, just + copy it. */ + + if (((rc.right - rc.left) > (int) wBitmapX) || + ((rc.bottom - rc.top) > (int) wBitmapY)) + { + StretchBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, + hdcSource, rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top, SRCCOPY); + } + + else + { + BitBlt(hdcTarget, 0, 0, rc.right - rc.left, + rc.bottom - rc.top, + hdcSource, rc.left, rc.top, SRCCOPY); + } + + /* Select the old source and destination bitmaps into the + source and destination DCs, and then delete the DCs and + the background brush. */ + + SelectObject(hdcSource, hbmpSourceOld); + SelectObject(hdcTarget, hbrTargetOld); + hbmpCheck = SelectObject(hdcTarget, hbmpTargetOld); + + DeleteObject(hbrBackground); + DeleteObject(hdcSource); + DeleteObject(hdcTarget); + + /* Return a handle to the new check-mark bitmap. */ + + return hbmpCheck; +} + +void mswCreateCheckBitmaps() +{ + checked = GetMyCheckBitmaps( CHECK ); + unchecked = GetMyCheckBitmaps( UNCHECK ); + checkedRadio = GetMyCheckBitmaps( RADIOCHECK ); + uncheckedRadio = GetMyCheckBitmaps( RADIOUNCHECK ); + +} + +wMenuRadio_p wMenuRadioCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wMenuCallBack_p action, + void *data ) +{ + wMenuRadio_p mi; + int rc; + char label[80]; + char *cp; + char ac; + UINT vk; + long modifier; + + mi = (wMenuRadio_p)createMenuItem( m, M_RADIO, helpStr, labelStr, sizeof *mi ); + mi->action = action; + mi->data = data; + mi->mparent = m; + mi->acclKey = acclKey; + mi->enabled = TRUE; + strcpy( label, mi->labelStr ); + modifier = 0; + if ( acclKey != 0 ) { + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + cp = label + strlen( label ); + *cp++ = '\t'; + if (acclKey & WCTL ) { + strcpy( cp, "Ctrl+" ); + cp += 5; + modifier |= WKEY_CTRL; + } + if (acclKey & WALT ) { + strcpy( cp, "Alt+" ); + cp += 4; + modifier |= WKEY_ALT; + } + if (acclKey & WSHIFT ) { + strcpy( cp, "Shift+" ); + cp += 6; + modifier |= WKEY_SHIFT; + } + *cp++ = toupper( (char)(acclKey & 0xFF) ); + *cp++ = '\0'; + ac = (char)(acclKey & 0xFF); + if (isalpha(ac)) { + ac = tolower( ac ); + } + vk = VkKeyScan( ac ); + if ( vk & 0xFF00 ) + modifier |= WKEY_SHIFT; + acclTable(acclTable_da.cnt-1).acclKey = (modifier<<8) | (vk&0x00FF); + acclTable(acclTable_da.cnt-1).mp = (wMenuPush_p)mi; + } + rc = AppendMenu( m->menu, MF_STRING, mi->index, label ); + + /* add the correct bitmaps for radio buttons */ + + rc = SetMenuItemBitmaps(m->menu, mi->index, FALSE, uncheckedRadio, checkedRadio ); + + if( m->radioGroup == NULL ) { + m->radioGroup = malloc( sizeof( struct radioButtonGroup )); + assert( m->radioGroup ); + m->radioGroup->firstButton = mi->index; + } else { + m->radioGroup->lastButton = mi->index; + } + + return mi; +} + +void wMenuRadioSetActive(wMenuRadio_p mi ) +{ + BOOL rc; + + rc = CheckMenuRadioItem( mi->mparent->menu, + mi->mparent->radioGroup->firstButton, + mi->mparent->radioGroup->lastButton, + mi->index, + MF_BYCOMMAND ); +} + + +wMenuPush_p wMenuPushCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wMenuCallBack_p action, + void *data ) +{ + wMenuPush_p mi; + int rc; + char label[80]; + char *cp; + char ac; + UINT vk; + long modifier; + + mi = (wMenuPush_p)createMenuItem( m, M_PUSH, helpStr, labelStr, sizeof *mi ); + mi->action = action; + mi->data = data; + mi->mparent = m; + mi->acclKey = acclKey; + mi->enabled = TRUE; + strcpy( label, mi->labelStr ); + modifier = 0; + if ( acclKey != 0 ) { + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + cp = label + strlen( label ); + *cp++ = '\t'; + if (acclKey & WCTL ) { + strcpy( cp, "Ctrl+" ); + cp += 5; + modifier |= WKEY_CTRL; + } + if (acclKey & WALT ) { + strcpy( cp, "Alt+" ); + cp += 4; + modifier |= WKEY_ALT; + } + if (acclKey & WSHIFT ) { + strcpy( cp, "Shift+" ); + cp += 6; + modifier |= WKEY_SHIFT; + } + *cp++ = toupper( (char)(acclKey & 0xFF) ); + *cp++ = '\0'; + ac = (char)(acclKey & 0xFF); + if (isalpha(ac)) { + ac = tolower( ac ); + } + vk = VkKeyScan( ac ); + if ( vk & 0xFF00 ) + modifier |= WKEY_SHIFT; + acclTable(acclTable_da.cnt-1).acclKey = (modifier<<8) | (vk&0x00FF); + acclTable(acclTable_da.cnt-1).mp = mi; + } + rc = AppendMenu( m->menu, MF_STRING, mi->index, label ); + return mi; +} + + +void wMenuPushEnable( + wMenuPush_p mi, + BOOL_T enable ) +{ + EnableMenuItem( mi->mparent->menu, mi->index, + MF_BYCOMMAND|(enable?MF_ENABLED:(MF_DISABLED|MF_GRAYED)) ); + mi->enabled = enable; +} + + +wMenu_p wMenuMenuCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr ) +{ + wMenu_p mm; + int rc; + + mm = (wMenu_p)createMenuItem( NULL, M_MENU, NULL, labelStr, sizeof *mm ); + mm->menu = CreatePopupMenu(); + mm->mmtype = MM_MENU; + /*mm->parent = (wControl_p)m;*/ + mm->first = mm->last = NULL; + + rc = AppendMenu( m->menu, MF_STRING|MF_ENABLED|MF_POPUP, (UINT)mm->menu, mm->labelStr ); + + return mm; +} + +void wMenuSeparatorCreate( + wMenu_p m ) +{ + int rc; + createMenuItem( m, M_SEPARATOR, NULL, NULL, sizeof *(wMenuItem_p)NULL ); + rc = AppendMenu( m->menu, MF_SEPARATOR, (UINT)0, NULL ); +} + +/* + ***************************************************************************** + * + * Menu List + * + ***************************************************************************** + */ + + +static void appendItem( + wMenuListItem_p ml, + wMenuListItem_p mi ) +{ + mi->right = ml->right; + ml->right->left = mi; + mi->left = ml; + ml->right = mi; +} + + +static void removeItem( + wMenuListItem_p mi ) +{ + mi->left->right = mi->right; + mi->right->left = mi->left; + mi->right = mi->left = mi; +} + + +wMenuList_p wMenuListCreate( + wMenu_p m, + const char * helpStr, + int max, + wMenuListCallBack_p action ) +{ + wMenuList_p mi; + mi = (wMenuList_p)createMenuItem( m, M_LIST, helpStr, NULL, sizeof *mi ); + mi->count = 0; + mi->max = max; + mi->mlparent = m; + mi->action = action; + mi->right = mi->left = (wMenuListItem_p)mi; + return mi; +} + + +int getMlistOrigin( wMenu_p m, wMenuList_p ml ) +{ + wMenuItem_p mi; + int count; + count = 0; + for ( mi = m->first; mi != NULL; mi = mi->mnext ) { + switch( mi->mtype ) { + case M_SEPARATOR: + case M_PUSH: + case M_MENU: + count++; + break; + case M_LIST: + if (mi == (wMenuItem_p)ml) + return count; + count += ((wMenuList_p)mi)->count; + break; + default: + mswFail( "getMlistOrigin" ); + } + } + return count; +} + + +void wMenuListAdd( + wMenuList_p ml, + int index, + const char * labelStr, + void * data ) +{ + int origin; + wMenuListItem_p wl_p; + wMenuListItem_p mi; + int count; + int rc; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p!=(wMenuListItem_p)ml; count++,wl_p=wl_p->right ) { + if (wl_p->labelStr != NULL && strcmp( labelStr, wl_p->labelStr ) == 0) { + /* move item */ + if (count != index) { + RemoveMenu( ml->mlparent->menu, origin+count, MF_BYPOSITION ); + removeItem( wl_p ); + goto add; + } + ((wMenuListItem_p)wl_p)->data = data; + return; + } + } + if (ml->max > 0 && ml->count >= ml->max) { + RemoveMenu( ml->mlparent->menu, origin+ml->count-1, MF_BYPOSITION ); + wl_p = ml->left; + removeItem( ml->left ); +add: + ml->count--; + if (wl_p->labelStr ) + free( CAST_AWAY_CONST wl_p->labelStr ); + wl_p->labelStr = mswStrdup( labelStr ); + } else { + wl_p = (wMenuListItem_p)createMenuItem( NULL, M_LISTITEM, NULL, + labelStr, sizeof *wl_p ); + } + ((wMenuListItem_p)wl_p)->data = data; + ((wMenuListItem_p)wl_p)->action = ml->action; + if (index < 0 || index > ml->count) + index = ml->count; + for ( mi=(wMenuListItem_p)ml,count=0; count<index; mi=mi->right,count++); + rc = InsertMenu( ml->mlparent->menu, origin+index, + MF_BYPOSITION|MF_STRING, wl_p->index, wl_p->labelStr ); + appendItem( mi, wl_p ); + ml->count++; +} + + +void wMenuListDelete( + wMenuList_p ml, + const char * labelStr ) +{ + int origin, count; + wMenuListItem_p wl_p; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p!=(wMenuListItem_p)ml; count++,wl_p=wl_p->right ) { + if (wl_p->labelStr != NULL && strcmp( labelStr, wl_p->labelStr ) == 0) { + /* delete item */ + mswUnregister( wl_p->index ); + RemoveMenu( ml->mlparent->menu, origin+count, MF_BYPOSITION ); + removeItem( wl_p ); + ml->count--; + free( wl_p ); + return; + } + } +} + + +const char * wMenuListGet( + wMenuList_p ml, + int index, + void ** data ) +{ + int origin, count; + wMenuListItem_p wl_p; + + if (index >= ml->count) + return NULL; + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p&&count<index; count++,wl_p=wl_p->right ); + if (wl_p==NULL) + return NULL; + if ( data ) + *data = wl_p->data; + return wl_p->labelStr; +} + + +void wMenuListClear( + wMenuList_p ml ) +{ + int origin, count; + wMenuListItem_p wl_p, wl_q; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; count<ml->count; count++,wl_p=wl_q ) { + /* delete item */ + mswUnregister( wl_p->index ); + RemoveMenu( ml->mlparent->menu, origin, MF_BYPOSITION ); + wl_q = wl_p->right; + free( wl_p ); + } + ml->count = 0; + ml->right = ml->left = (wMenuListItem_p)ml; +} + + + +wMenuToggle_p wMenuToggleCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wBool_t set, + wMenuToggleCallBack_p action, + void * data ) +{ + wMenuToggle_p mt; + int rc; + + mt = (wMenuToggle_p)createMenuItem( m, M_TOGGLE, helpStr, labelStr, sizeof *mt ); + /*setAcclKey( m->parent, m->menu, mt->menu_item, acclKey );*/ + mt->action = action; + mt->data = data; + mt->mparent = m; + mt->enabled = TRUE; + mt->parentMenu = m; + rc = AppendMenu( m->menu, MF_STRING, mt->index, labelStr ); + wMenuToggleSet( mt, set ); + return mt; +} + + +wBool_t wMenuToggleGet( + wMenuToggle_p mt ) +{ + return (GetMenuState( mt->mparent->menu, mt->index, MF_BYCOMMAND ) & MF_CHECKED) != 0; +} + + +wBool_t wMenuToggleSet( + wMenuToggle_p mt, + wBool_t set ) +{ + wBool_t rc; + CheckMenuItem( mt->mparent->menu, mt->index, MF_BYCOMMAND|(set?MF_CHECKED:MF_UNCHECKED) ); + rc = (GetMenuState( mt->mparent->menu, mt->index, MF_BYCOMMAND ) & MF_CHECKED) != 0; + return rc; +} + +void wMenuToggleEnable( + wMenuToggle_p mt, + wBool_t enable ) +{ + EnableMenuItem( mt->mparent->menu, mt->index, + MF_BYCOMMAND|(enable?MF_ENABLED:(MF_DISABLED|MF_GRAYED)) ); + mt->enabled = enable; +} + +/* + ***************************************************************************** + * + * Menu Create + * + ***************************************************************************** + */ + + +void mswMenuMove( + wMenu_p m, + wPos_t x, + wPos_t y ) +{ + wControl_p b; + b = (wControl_p)m->parent; + if (b && b->hWnd) + if (!SetWindowPos( b->hWnd, HWND_TOP, x, y, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("mswMenuMove"); +} + + +static void pushMenuButt( + void * data ) +{ + wMenu_p m = (wMenu_p)data; + RECT rect; + mswAllowBalloonHelp = FALSE; + GetWindowRect( m->hWnd, &rect ); + TrackPopupMenu( m->menu, TPM_LEFTALIGN, rect.left, rect.bottom, + 0, ((wControl_p)(m->parent))->hWnd, NULL ); +} + + +wMenu_p wMenuCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option ) +{ + wMenu_p m; + wControl_p b; + long buttOption = 0; + const char * label = labelStr; + + if (option & BM_ICON) { + buttOption = BO_ICON; + label = "ICON"; + } + m = (wMenu_p)createMenuItem( NULL, M_MENU, helpStr, label, sizeof *m ); + m->button = wButtonCreate( parent, x, y, helpStr, labelStr, + buttOption, 0, pushMenuButt, (void*)m ); + b = (wControl_p)m->button; + m->parent = b->parent; + m->x = b->x; + m->y = b->y; + m->w = b->w; + m->h = b->h; + m->hWnd = b->hWnd; + m->helpStr = b->helpStr; + + m->menu = CreatePopupMenu(); + m->mmtype = MM_BUTT; + m->first = m->last = NULL; + + return m; +} + + +wMenu_p wMenuBarAdd( + wWin_p w, + const char * helpStr, + const char * labelStr ) +{ + HMENU menu; + wMenu_p m; + int rc; + + menu = GetMenu( ((wControl_p)w)->hWnd ); + if (menu == (HMENU)0) { + menu = CreateMenu(); + SetMenu( ((wControl_p)w)->hWnd, menu ); + } + + m = (wMenu_p)createMenuItem( NULL, M_MENU, helpStr, labelStr, sizeof *m ); + m->menu = CreateMenu(); + m->parent = w; + m->mmtype = MM_BAR; + m->first = m->last = NULL; + + rc = AppendMenu( menu, MF_STRING|MF_POPUP|MF_ENABLED, (UINT)m->menu, labelStr ); + + DrawMenuBar( ((wControl_p)w)->hWnd ); + return m; +} + + + +wMenu_p wMenuPopupCreate( + wWin_p w, + const char * labelStr ) +{ + wMenu_p m; + long buttOption = 0; + const char * label = labelStr; + + m = (wMenu_p)createMenuItem( NULL, M_MENU, NULL, label, sizeof *m ); + m->button = NULL; + m->parent = w; + m->x = 0; + m->y = 0; + m->w = 0; + m->h = 0; + m->hWnd = ((wControl_p)w)->hWnd; + m->helpStr = NULL; + + m->menu = CreatePopupMenu(); + m->mmtype = MM_POPUP; + m->first = m->last = NULL; + + return m; +} + + +void wMenuPopupShow( wMenu_p mp ) +{ + POINT pt; + GetCursorPos( &pt ); + TrackPopupMenu( mp->menu, TPM_LEFTALIGN, pt.x, pt.y, 0, mp->hWnd, NULL ); +} + +/*-----------------------------------------------------------------*/ + +void wMenuSetTraceCallBack( + wMenu_p m, + wMenuTraceCallBack_p func, + void * data ) +{ + m->traceFunc = func; + m->traceData = data; +} + +wBool_t wMenuAction( + wMenu_p m, + const char * label ) +{ + wMenuItem_p mi; + wMenuToggle_p mt; + wBool_t set; + for ( mi = m->first; mi != NULL; mi = (wMenuItem_p)mi->mnext ) { + if ( mi->labelStr != NULL && strcmp( mi->labelStr, label ) == 0 ) { + switch( mi->mtype ) { + case M_SEPARATOR: + break; + case M_PUSH: + if ( ((wMenuPush_p)mi)->enabled == FALSE ) + wBeep(); + else + ((wMenuPush_p)mi)->action( ((wMenuPush_p)mi)->data ); + break; + case M_TOGGLE: + mt = (wMenuToggle_p)mi; + if ( mt->enabled == FALSE ) { + wBeep(); + } else { + set = wMenuToggleGet( mt ); + wMenuToggleSet( mt, !set ); + mt->action( set, mt->data ); + } + break; + case M_MENU: + break; + case M_LIST: + break; + default: + fprintf(stderr, "Oops: wMenuAction\n"); + } + return TRUE; + } + } + return FALSE; +} diff --git a/app/wlib/mswlib/mswmisc.c b/app/wlib/mswlib/mswmisc.c new file mode 100644 index 0000000..fc1dbe6 --- /dev/null +++ b/app/wlib/mswlib/mswmisc.c @@ -0,0 +1,2778 @@ +/** \file mswmisc.c + * Basic windows functions and main entry point for application. + * + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswmisc.c,v 1.28 2010-04-28 04:04:38 dspagnol Exp $ + */ + +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2005 Dave Bullis, 2009 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. + */ + +#define _WIN32_WINNT 0x0500 +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <stdio.h> +#include <assert.h> +#include <htmlhelp.h> +#include "mswint.h" +#include "i18n.h" + +#if _MSC_VER > 1300 + #define stricmp _stricmp + #define strnicmp _strnicmp + #define strdup _strdup +#endif + +#define OFN_LONGFILENAMES 0x00200000L + +char * mswStrdup( const char * ); + +#define PAUSE_TIMER (901) +#define ALARM_TIMER (902) +#define BALLOONHELP_TIMER (903) +#define TRIGGER_TIMER (904) + +#define WANT_LITTLE_LABEL_FONT + +#ifndef WANT_LITTLE_LABEL_FONT +#define LABELFONTDECL +#define LABELFONTSELECT +#define LABELFONTRESET +#else +#define LABELFONTDECL HFONT hFont; +#define LABELFONTRESET if (!mswThickFont) {SelectObject( hDc, hFont );} +#define LABELFONTSELECT if (!mswThickFont) {hFont = SelectObject( hDc, mswLabelFont );} +#endif + +/* + * EXPORTED VARIABLES + */ + +long debugWindow = 0; +HINSTANCE mswHInst; +HWND mswHWnd = (HWND)0; + +const char *mswDrawWindowClassName = "DRAWWINDOW"; +char mswTmpBuff[1024]; +int mswEditHeight; +int mswAllowBalloonHelp = TRUE; +int mswGroupStyle; +HFONT mswOldTextFont; +HFONT mswLabelFont; +long mswThickFont = 1; +double mswScale = 1.0; + +callBacks_t *mswCallBacks[CALLBACK_CNT]; + +void closeBalloonHelp( void ); +static wControl_p getControlFromCursor( HWND, wWin_p * ); +/* + * LOCAL VARIABLES + */ + +struct wWin_t { + WOBJ_COMMON + wPos_t lastX, lastY; + wPos_t padX, padY; + wControl_p first, last; + wWinCallBack_p winProc; + BOOL_T busy; +#ifdef OWNERICON + HBITMAP wicon_bm; + wPos_t wicon_w, wicon_h; +#endif + DWORD baseStyle; + wControl_p focusChainFirst; + wControl_p focusChainLast; + char * nameStr; + wBool_t centerWin; + DWORD style; + int isBusy; + int pendingShow; + int modalLevel; + }; + +static needToDoPendingShow = FALSE; + +/* System metrics: */ +static int mTitleH; +static int mFixBorderW; +static int mFixBorderH; +static int mResizeBorderW; +static int mResizeBorderH; +static int mMenuH; +static int screenWidth = 0, screenHeight = 0; + +wWin_p mswWin = NULL; +wWin_p winFirst, winLast; + +static long count51 = 0; + +static UINT alarmTimer; +static UINT pauseTimer; +static UINT balloonHelpTimer = (UINT)0; +static UINT triggerTimer; + +static UINT balloonHelpTimeOut = 500; +static wControl_p balloonHelpButton = NULL; +static enum { balloonHelpIdle , balloonHelpWait, balloonHelpShow } balloonHelpState = balloonHelpIdle; +static HWND balloonHelpHWnd = (HWND)0; +static int balloonHelpFontSize = 8; +static char balloonHelpFaceName[] = "MS Sans Serif"; +static HFONT balloonHelpOldFont; +static HFONT balloonHelpNewFont; +static int balloonHelpEnable = TRUE; +static wControl_p balloonControlButton = NULL; + +static BOOL_T helpInitted = FALSE; +static DWORD dwCookie; + +#define CONTROL_BASE (1) +typedef struct { + wControl_p b; + } controlMap_t; +dynArr_t controlMap_da; +#define controlMap(N) DYNARR_N(controlMap_t,controlMap_da,N) + + +static char * appName; +static char * helpFile; +char *mswProfileFile; + +static wBalloonHelp_t * balloonHelpStrings; + +static wCursor_t curCursor = wCursorNormal; + +#ifdef HELPSTR +static FILE * helpStrF; +#endif +static int inMainWndProc = FALSE; + +int newHelp = 1; + +static wBool_t mswWinBlockEnabled = TRUE; + +static FILE * dumpControlsF; +static int dumpControls; + +extern char *userLocale; + + +/* + ***************************************************************************** + * + * Internal Utility functions + * + ***************************************************************************** + */ + + +DWORD GetTextExtent( + HDC hDc, + CHAR * str, + UINT len ) +{ + SIZE size; + GetTextExtentPoint( hDc, str, len, &size ); + return size.cx + (size.cy<<16); +} + + +static char * controlNames[] = { + "MAIN", "POPUP", + "BUTTON", "STRING", "INTEGER", "FLOAT", + "LIST", "DROPLIST", "COMBOLIST", + "RADIO", "TOGGLE", + "DRAW", "TEXT", "MESSAGE", "LINES", + "MENUITEM", "CHOICEITEM", "BOX" }; + +static void doDumpControls(void) +{ + wControl_p b; + int inx; + if ( !dumpControls ) + return; + if ( !dumpControlsF ) { + dumpControlsF = fopen( "controls.lst", "w" ); + if ( !dumpControlsF ) + abort(); + } + for ( inx=0; inx<controlMap_da.cnt-1; inx++ ) { + b = controlMap(inx).b; + if ( b ) { + fprintf( dumpControlsF, "[%0.3d] [%x] %s %s %s\n", inx, + b->hWnd, + (b->type>=0&&b->type<=B_BOX?controlNames[b->type]:"NOTYPE"), + (b->labelStr?b->labelStr:"<NULL>"), + (b->helpStr?b->helpStr:"<NULL>") ); + } else { + fprintf( dumpControlsF, "[%0.3d] <NULL>\n", inx ); + } + } + fflush( dumpControlsF ); + fclose( dumpControlsF ); + dumpControls = 0; +} + +void mswFail( const char * where ) +{ + sprintf( mswTmpBuff, "%s\n# Controls %d", where, controlMap_da.cnt ); + MessageBox( NULL, mswTmpBuff, "FAIL", MB_TASKMODAL|MB_OK ); + doDumpControls(); +} +/* +static UINT curSysRes = 100; +static UINT curGdiRes = 100; +static UINT curUsrRes = 100; +static UINT curMinRes = 100; +*/ + +wControl_p mswMapIndex( INDEX_T inx ) +{ + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) { + mswFail("mswMapIndex- bad index"); + exit(1); + } + return controlMap(inx-CONTROL_BASE).b; +} + + +void mswRepaintLabel( HWND hWnd, wControl_p b ) +{ + HDC hDc; + HBRUSH oldBrush, newBrush; + RECT rect; + DWORD dw; + LABELFONTDECL + + + if (b->labelStr) { + hDc = GetDC( hWnd ); + LABELFONTSELECT + newBrush = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) ); + oldBrush = SelectObject( hDc, newBrush ); + dw = GetTextExtent( hDc, CAST_AWAY_CONST b->labelStr, strlen(b->labelStr) ); + rect.left = b->labelX; + rect.top = b->labelY; + rect.right = b->labelX + LOWORD(dw); + rect.bottom = b->labelY + HIWORD(dw); + FillRect( hDc, &rect, newBrush ); + DeleteObject( SelectObject( hDc, oldBrush ) ); + /*SetBkMode( hDc, OPAQUE );*/ + SetBkColor( hDc, GetSysColor( COLOR_BTNFACE ) ); + if (!TextOut( hDc, b->labelX, b->labelY, b->labelStr, strlen(b->labelStr) ) ) + mswFail( "Repainting text label" ); + LABELFONTRESET + ReleaseDC( hWnd, hDc ); + } +} + + + +int mswRegister( + wControl_p w ) +{ + int index; + DYNARR_APPEND( controlMap_t, controlMap_da, 25 ); + index = controlMap_da.cnt-1+CONTROL_BASE; + controlMap(controlMap_da.cnt-1).b = (wControl_p)w; + return index; +} + + +void mswUnregister( + int index ) +{ + if (index < 0 || index > controlMap_da.cnt) { + mswFail("mswMapIndex- bad index"); + exit(1); + } + controlMap(index-CONTROL_BASE).b = NULL; +} + +void * mswAlloc( + wWin_p parent, + wType_e type, + const char * labelStr, + int size, + void * data, + int * index ) +{ + wControl_p w = (wControl_p)calloc( 1, size ); + + if (w == NULL) + abort(); + *index = mswRegister( w ); + w->type = type; + w->next = NULL; + w->parent = parent; + w->x = 0; + w->y = 0; + w->w = 0; + w->h = 0; + w->option = 0; + w->labelX = w->labelY = 0; + w->labelStr = labelStr; + w->helpStr = NULL; + w->hWnd = (HWND)0; + w->data = data; + w->focusChainNext = NULL; + w->shown = TRUE; + return w; +} + + +void mswComputePos( + wControl_p b, + wPos_t origX, + wPos_t origY ) +{ + wWin_p w = b->parent; + + if (origX >= 0) + b->x = origX; + else + b->x = w->lastX + (-origX) - 1; + if (origY >= 0) + b->y = origY; + else + b->y = w->lastY + (-origY) - 1; + + b->labelX = b->x; + b->labelY = b->y+2; + + if (b->labelStr) { + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( w->hWnd ); + LABELFONTSELECT + lab_l = strlen(b->labelStr); + dw = GetTextExtent( hDc, CAST_AWAY_CONST b->labelStr, lab_l ); + b->labelX -= LOWORD(dw) + 5; + LABELFONTRESET + ReleaseDC( w->hWnd, hDc ); + } +} + +void mswAddButton( + wControl_p b, + BOOL_T paintLabel, + const char * helpStr ) +{ + wWin_p w = b->parent; + BOOL_T resize = FALSE; + RECT rect; + + if (w->first == NULL) { + w->first = b; + } else { + w->last->next = b; + } + w->last = b; + b->next = NULL; + b->parent = w; + w->lastX = b->x + b->w; + w->lastY = b->y + b->h; + if ((w->option&F_AUTOSIZE)!=0 && w->lastX > w->w) { + w->w = w->lastX; + resize = TRUE; + } + if ((w->option&F_AUTOSIZE)!=0 && w->lastY > w->h) { + w->h = w->lastY; + resize = TRUE; + } + + if (resize) { + w->busy = TRUE; + rect.left = 0; + rect.top = 0; + rect.right = w->w+w->padX; + rect.bottom = w->h+w->padY; + AdjustWindowRect( &rect, w->style, (w->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + if (!SetWindowPos( w->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + SWP_NOMOVE)) + mswFail("SetWindowPos"); + w->busy = FALSE; + } + + if (paintLabel) + mswRepaintLabel( w->hWnd, (wControl_p)b ); + + if (helpStr == NULL) + return; + b->helpStr = mswStrdup( helpStr ); + +#ifdef HELPSTR + if (helpStrF) + fprintf( helpStrF, "HELPSTR - %s\n", helpStr?helpStr:"<>" ); +#endif +} + + +void mswResize( + wWin_p w ) +{ + wControl_p b; + RECT rect; + + w->lastX = 0; + w->lastY = 0; + for (b=w->first; b; b=b->next) { + if (w->lastX < (b->x + b->w)) + w->lastX = b->x + b->w; + if (w->lastY < (b->y + b->h)) + w->lastY = b->y + b->h; + } + + if (w->option&F_AUTOSIZE) { + w->w = w->lastX; + w->h = w->lastY; + w->busy = TRUE; + rect.left = 0; + rect.top = 0; + rect.right = w->w + w->padX; + rect.bottom = w->h + w->padY; + AdjustWindowRect( &rect, w->style, (w->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + if (!SetWindowPos( w->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + SWP_NOMOVE|SWP_NOZORDER)) + mswFail("SetWindowPos"); + w->busy = FALSE; + } +} + + + +void mswChainFocus( + wControl_p b ) +{ + wWin_p w; + w = b->parent; + if (w->option&F_NOTAB) + return; + if (b->option&BO_NOTAB) + return; + if (w->focusChainFirst == NULL) { + w->focusChainFirst = w->focusChainLast = w->focusChainNext = b; + b->focusChainNext = b; + } else { + w->focusChainLast->focusChainNext = b; + w->focusChainLast = b; + b->focusChainNext = w->focusChainFirst; + } +} + +void mswSetFocus( + wControl_p b ) +{ + if (b && b->type != B_MENUITEM && b->focusChainNext) + b->parent->focusChainNext = b; +} + +/* + ****************************************************************************** + * + * Main and Popup Windows + * + ****************************************************************************** + */ + +static void getSavedSizeAndPos( + long option, + const char * nameStr, + wPos_t *rw, + wPos_t *rh, + wPos_t *rx, + wPos_t *ry, + int *showCmd ) +{ + int x, y, w, h; + const char *cp; + char *cq; + int state; + + *showCmd = SW_SHOWNORMAL; + + if ( (option&F_RECALLPOS) && nameStr ) { + if ( (option & F_RESIZE) && + (cp = wPrefGetString( "msw window size", nameStr)) && + (state = (int)strtol( cp, &cq, 10 ), cp != cq) && + (cp = cq, w = (wPos_t)strtod( cp, &cq ), cp != cq ) && + (cp = cq, h = (int)strtod( cp, &cq ), cp != cq) + ) { + if (state == 1) + *showCmd = SW_SHOWMINIMIZED; + else if (state == 2) + *showCmd = SW_SHOWMAXIMIZED; + if (w < 10) + w = 10; + if (h < 10) + h = 10; + if (w > screenWidth) + w = screenWidth; + if (h > screenHeight) + h = screenHeight; + *rw = w; + *rh = h; + } + + if ((cp = wPrefGetString( "msw window pos", nameStr)) && + (x = (wPos_t)strtod( cp, &cq ), cp != cq) && + (cp = cq, y = (wPos_t)strtod( cp, &cq ), cp != cq) + ) { + if (y < 0) + y = 0; + if (x < 0) + x = 0; + if ( y > screenHeight-40 ) + y = screenHeight-40; + if ( x > screenWidth-40 ) + x = screenWidth-40; + *rx = x; + *ry = y; + } + } +} + + +static wWin_p winCommonCreate( + HWND hWnd, + int typ, + long option, + const char * className, + long style, + const char * labelStr, + wWinCallBack_p winProc, + wPos_t w, + wPos_t h, + void * data, + const char * nameStr, + int * showCmd ) +{ + wWin_p win; + int index; + wPos_t ww, hh, xx, yy; + RECT rect; + + win = (wWin_p)mswAlloc( NULL, typ, mswStrdup(labelStr), sizeof *win, data, &index ); + win->option = option; + win->first = win->last = NULL; + win->lastX = 0; + win->lastY = 0; + win->winProc = winProc; + win->centerWin = TRUE; + win->modalLevel = 0; +#ifdef OWNERICON + win->wicon_bm = (HBITMAP)0; +#endif + win->busy = TRUE; + ww = hh = xx = yy = CW_USEDEFAULT; + getSavedSizeAndPos( option, nameStr, &ww, &hh, &xx, &yy, showCmd ); + if (xx != CW_USEDEFAULT) + win->centerWin = FALSE; + if (option & F_RESIZE) { + style |= WS_THICKFRAME; + if ( ww != CW_USEDEFAULT ) { + w = ww; + h = hh; + option &= ~F_AUTOSIZE; + win->option = option; + } + } + + if ( option & F_AUTOSIZE ) { + win->padX = w; + win->padY = h; + } else { + win->padX = 0; + win->padY = 0; + win->w = w; + win->h = h; + } + win->style = style; + rect.left = 0; + rect.top = 0; + rect.right = win->w + win->padX; + rect.bottom = win->h + win->padY; + AdjustWindowRect( &rect, win->style, (win->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + win->hWnd = CreateWindow( className, labelStr, style, + xx, yy, + rect.right-rect.left, rect.bottom-rect.top, + hWnd, NULL, + mswHInst, NULL ); + if (win->hWnd == (HWND)0) { + mswFail( "CreateWindow(POPUP)" ); + } else { + SetWindowWord( win->hWnd, 0, (WORD)index ); + } + win->baseStyle = WS_GROUP; + win->focusChainFirst = win->focusChainLast = win->focusChainNext = NULL; + if (winFirst == NULL) { + winFirst = winLast = win; + } else { + winLast->next = (wControl_p)win; + winLast = win; + } +#ifdef HELPSTR + if (helpStrF) + fprintf( helpStrF, "WINDOW - %s\n", labelStr ); +#endif + win->nameStr = mswStrdup( nameStr ); + if (typ == W_MAIN) + mswInitColorPalette(); +#ifdef LATER + hDc = GetDC( win->hWnd ); + oldHPal = SelectPalette( hDc, mswPalette, 0 ); + ReleaseDC( win->hWnd, hDc ); +#endif + return win; +} + +void wInitAppName(char *_appName) +{ + appName = (char *)malloc( strlen(_appName) + 1 ); + strcpy(appName, _appName); +} + + +/** + * Initialize the application's main window. This function does the necessary initialization + * of the application including creation of the main window. + * + * \param name IN internal name of the application. Used for filenames etc. + * \param x IN size + * \param y IN size + * \param helpStr IN ?? + * \param labelStr IN window title + * \param nameStr IN ?? + * \param option IN options for window creation + * \param winProc IN pointer to main window procedure + * \param data IN ?? + * \return window handle or NULL on error + */ + +wWin_p wWinMainCreate( + const char * name, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + const char * nameStr, + long option, + wWinCallBack_p winProc, + void * data ) +{ + wWin_p w; + RECT rect; + const char * appDir; + const char * libDir; + int showCmd; + int error; + HDC hDc; + TEXTMETRIC tm; + char *pos; + char * configName; + + /* check for configuration name */ + if( pos = strchr( name, ';' )) { + /* if found, split application name and configuration name */ + configName = (char *)malloc( strlen( name ) + 1 ); + strcpy( configName, pos + 1 ); + } else { + /* if not found, application name and configuration name are same */ + configName = (char*)malloc( strlen(name)+1 ); + strcpy( configName, name ); + } + + appDir = wGetAppWorkDir(); + if ( appDir == NULL ) { + free( configName ); + return NULL; + } + mswProfileFile = (char*)malloc( strlen(appDir)+1+strlen(configName)+1+3+1 ); + wsprintf( mswProfileFile, "%s\\%s.ini", appDir, configName ); + free( configName ); + + error = WritePrivateProfileString( "mswtest", "test", "ok", mswProfileFile ); + if ( error <= 0 ) { + sprintf( mswTmpBuff, "Can not write to %s.\nPlease make sure the directory exists and is writable", mswProfileFile ); + wNoticeEx( NT_ERROR, mswTmpBuff, "Ok", NULL ); + return NULL; + } + libDir = wGetAppLibDir(); + /* length of path + \ + length of filename + . + length of extension + \0 */ + helpFile = (char*)malloc( strlen(libDir) + 1 + strlen(appName) + 1 + 3 + 1 ); + wsprintf( helpFile, "%s\\%s.chm", libDir, appName ); + + wPrefGetInteger( "msw tweak", "ThickFont", &mswThickFont, 0 ); + + showCmd = SW_SHOW; + w = winCommonCreate( NULL, W_MAIN, option|F_RESIZE, "MswMainWindow", + WS_OVERLAPPEDWINDOW, labelStr, winProc, x, y, data, + nameStr, &showCmd ); + 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 ); + } + ShowWindow( w->hWnd, showCmd ); + UpdateWindow( w->hWnd ); + GetWindowRect( w->hWnd, &rect ); + GetClientRect( w->hWnd, &rect ); + w->busy = FALSE; + + + return w; +} + +wWin_p wWinPopupCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + const char * nameStr, + long option, + wWinCallBack_p winProc, + void * data ) +{ + wWin_p w; + DWORD style; + HMENU sysMenu; + int showCmd; + static DWORD overlapped = WS_OVERLAPPED; + static DWORD popup = WS_POPUP; + + style = popup; + style |= WS_BORDER | WS_CAPTION | WS_SYSMENU; + w = winCommonCreate( parent?parent->hWnd:mswHWnd, W_POPUP, option, + "MswPopUpWindow", + style, labelStr, winProc, x, y, data, nameStr, &showCmd ); + + w->helpStr = mswStrdup( helpStr ); + + sysMenu = GetSystemMenu( w->hWnd, FALSE ); + if (sysMenu) { + DeleteMenu( sysMenu, SC_RESTORE, MF_BYCOMMAND ); + /*DeleteMenu( sysMenu, SC_MOVE, MF_BYCOMMAND );*/ + /*DeleteMenu( sysMenu, SC_SIZE, MF_BYCOMMAND );*/ + DeleteMenu( sysMenu, SC_MINIMIZE, MF_BYCOMMAND ); + DeleteMenu( sysMenu, SC_MAXIMIZE, MF_BYCOMMAND ); + DeleteMenu( sysMenu, SC_TASKLIST, MF_BYCOMMAND ); + DeleteMenu( sysMenu, 4, MF_BYPOSITION ); + } + w->busy = FALSE; + return w; +} + +void wWinSetBigIcon( + wWin_p win, + wIcon_p bm ) +{ +#ifdef OWNERICON + win->wicon_w = bm->w; + win->wicon_h = bm->h; + win->wicon_bm = mswCreateBitMap( + GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), RGB( 255, 255, 255 ), + bm->w, bm->h, bm->bits ); +#endif +} + + +void wWinSetSmallIcon( + wWin_p win, + wIcon_p bm ) +{ +#ifdef OWNERICON + win->wicon_w = bm->w; + win->wicon_h = bm->h; + win->wicon_bm = mswCreateBitMap( + GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), RGB( 255, 255, 255 ), + bm->w, bm->h, bm->bits ); +#endif +} + + +void wWinTop( + wWin_p win ) +{ + /*BringWindowToTop( win->hWnd );*/ + SetWindowPos( win->hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE ); + SetFocus( win->hWnd ); +} + + +DWORD mswGetBaseStyle( wWin_p win ) +{ + DWORD style; + style = win->baseStyle; + win->baseStyle = 0; + return style; +} + + +static wAccelKey_e translateExtKey( UINT wParam ) +{ + wAccelKey_e extChar; + extChar = wAccelKey_None; + switch( wParam ) { + case VK_DELETE: extChar = wAccelKey_Del; break; + case VK_INSERT: extChar = wAccelKey_Ins; break; + case VK_HOME: extChar = wAccelKey_Home; break; + case VK_END: extChar = wAccelKey_End; break; + case VK_PRIOR: extChar = wAccelKey_Pgup; break; + case VK_NEXT: extChar = wAccelKey_Pgdn; break; + case VK_UP: extChar = wAccelKey_Up; break; + case VK_DOWN: extChar = wAccelKey_Down; break; + case VK_RIGHT: extChar = wAccelKey_Right; break; + case VK_LEFT: extChar = wAccelKey_Left; break; + case VK_BACK: extChar = wAccelKey_Back; break; + /*case VK_F1: extChar = wAccelKey_F1; break;*/ + case VK_F2: extChar = wAccelKey_F2; break; + case VK_F3: extChar = wAccelKey_F3; break; + case VK_F4: extChar = wAccelKey_F4; break; + case VK_F5: extChar = wAccelKey_F5; break; + case VK_F6: extChar = wAccelKey_F6; break; + case VK_F7: extChar = wAccelKey_F7; break; + case VK_F8: extChar = wAccelKey_F8; break; + case VK_F9: extChar = wAccelKey_F9; break; + case VK_F10: extChar = wAccelKey_F10; break; + case VK_F11: extChar = wAccelKey_F11; break; + case VK_F12: extChar = wAccelKey_F12; break; + } + return extChar; +} + + +long notModKey; +int mswTranslateAccelerator( + HWND hWnd, + LPMSG pMsg ) +{ + long acclKey; + long state; + wWin_p win; + wControl_p b; + + if ( pMsg->message != WM_KEYDOWN ) + return FALSE; + acclKey = pMsg->wParam; + b = getControlFromCursor( pMsg->hwnd, &win ); + if ( win == NULL ) + return 0; + if ( b != NULL ) { + switch (b->type) { + case B_STRING: + case B_INTEGER: + case B_FLOAT: + case B_LIST: + case B_DROPLIST: + case B_COMBOLIST: + case B_TEXT: + return 0; + } + } + if ( acclKey == (long)VK_F1 ) { + closeBalloonHelp(); + if (!b && win) { + wHelp( win->helpStr ); + } else { + if (b->helpStr) + wHelp( b->helpStr ); + else if (b->parent) + wHelp( b->parent->nameStr ); + } + return 1; + } + /*acclKey = translateExtKey( (WORD)acclKey );*/ + state = 0; + if ( GetKeyState(VK_CONTROL) & 0x1000 ) + state |= WKEY_CTRL; + if ( GetKeyState(VK_MENU) & 0x1000 ) + state |= WKEY_ALT; + if ( GetKeyState(VK_SHIFT) & 0x1000 ) + state |= WKEY_SHIFT; + state <<= 8; + acclKey |= state; + if (pMsg->wParam > 0x12) + notModKey = TRUE; + return mswMenuAccelerator( win, acclKey ); +} + +/* + ****************************************************************************** + * + * Window Utilities + * + ****************************************************************************** + */ + + + +void wGetDisplaySize( POS_T * width, POS_T * height ) +{ + *width = screenWidth; + *height = screenHeight; +} + + +void wWinGetSize( wWin_p w, POS_T * width, POS_T * height ) +{ + RECT rect; + GetWindowRect( w->hWnd, &rect ); + GetClientRect( w->hWnd, &rect ); + w->w = rect.right - rect.left; + w->h = rect.bottom - rect.top; + *width = w->w; + *height = w->h; +} + + +void wWinSetSize( wWin_p w, POS_T width, POS_T height ) +{ + RECT rect; + w->w = width; + w->h = height; + rect.left = 0; + rect.top = 0; + rect.right = w->w /*+w->padX*/; + rect.bottom = w->h /*+w->padY*/; + AdjustWindowRect( &rect, w->style, (w->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + if (!SetWindowPos( w->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + SWP_NOMOVE|SWP_NOZORDER)) + mswFail("wWinSetSize"); + InvalidateRect( w->hWnd, NULL, TRUE ); +} + + +static int blocking; +static void blockingLoop( void ) +{ + MSG msg; + int myBlocking=blocking; + while (blocking>=myBlocking && GetMessage( &msg, NULL, 0, 0 )) { + if ( +#ifdef DOTRANSACCEL + (!TranslateAccelerator( mswWin->hWnd, hMswAccel, &msg )) && +#endif + (!mswTranslateAccelerator( mswWin->hWnd, &msg )) ) { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } +} + + +static void savePos( wWin_p win ) +{ + char posStr[20]; + WINDOWPLACEMENT windowPlace; + wPos_t w, h; + RECT rect; + + if ( win->nameStr && + IsWindowVisible( win->hWnd) /*&& !IsIconic( win->hWnd )*/ ) { + windowPlace.length = sizeof windowPlace; + GetWindowPlacement( win->hWnd, &windowPlace ); + if (win->option&F_RECALLPOS) { + wsprintf( posStr, "%d %d", + windowPlace.rcNormalPosition.left, + windowPlace.rcNormalPosition.top ); + wPrefSetString( "msw window pos", win->nameStr, posStr ); + if (win->option&F_RESIZE) { + GetClientRect( win->hWnd, &rect ); + w = rect.right - rect.left; + h = rect.bottom - rect.top; + w = windowPlace.rcNormalPosition.right - windowPlace.rcNormalPosition.left; + h = windowPlace.rcNormalPosition.bottom - windowPlace.rcNormalPosition.top; + w -= mResizeBorderW*2; + h -= mResizeBorderH*2 + mTitleH; + if (win->option&F_MENUBAR) + h -= mMenuH; + wsprintf( posStr, "%d %d %d", + ( windowPlace.showCmd == SW_SHOWMINIMIZED ? 1 : + (windowPlace.showCmd == SW_SHOWMAXIMIZED ? 2 : 0 ) ), + w, h ); + wPrefSetString( "msw window size", win->nameStr, posStr ); + } + } + } +} + + +void wWinShow( + wWin_p win, + BOOL_T show ) +{ + wPos_t x, y; + wWin_p win1; + + win->busy = TRUE; + if (show) { + if (win->centerWin) { + x = (screenWidth-win->w)/2; + y = (screenHeight-win->h)/2; + if (x<0) + y = 0; + if (x<0) + y = 0; + if (!SetWindowPos( win->hWnd, HWND_TOP, x, y, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail( "wWinShow:SetWindowPos()" ); + } + win->centerWin = FALSE; + win->shown = TRUE; + if (mswHWnd == (HWND)0 || !IsIconic(mswHWnd) ) { + ShowWindow( win->hWnd, SW_SHOW ); + if (win->focusChainFirst) { + SetFocus( win->focusChainFirst->hWnd ); + } + win->pendingShow = FALSE; + if ( mswWinBlockEnabled && (win->option & F_BLOCK) ) { + blocking++; + inMainWndProc = FALSE; + for ( win1 = winFirst; win1; win1=(wWin_p)win1->next ) { + if ( win1->shown && win1 != win ) { + if (win1->modalLevel == 0 ) + EnableWindow( win1->hWnd, FALSE ); + win1->modalLevel++; + } + } + win->busy = FALSE; + blockingLoop(); + } + } else { + win->pendingShow = TRUE; + needToDoPendingShow = TRUE; + } + } else { + savePos( win ); + ShowWindow( win->hWnd, SW_HIDE ); + /*SetWindowPos( win->hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_HIDEWINDOW );*/ + if ( mswWinBlockEnabled && (win->option & F_BLOCK) ) { + blocking--; + for ( win1 = winFirst; win1; win1=(wWin_p)win1->next ) { + if ( win1->shown && win1 != win ) { + if ( win1->modalLevel > 0 ) + win1->modalLevel--; + if (win1->modalLevel == 0 ) + EnableWindow( win1->hWnd, TRUE ); + } + } + } + savePos( win ); + win->pendingShow = FALSE; + win->shown = FALSE; + } + win->busy = FALSE; +} + + +void wWinBlockEnable( + wBool_t enabled ) +{ + mswWinBlockEnabled = enabled; +} + + +wBool_t wWinIsVisible( + wWin_p w ) +{ + return IsWindowVisible(w->hWnd); +} + + +void wWinSetTitle( + wWin_p w, + const char * title ) +{ + SetWindowText( w->hWnd, title ); +} + + +void wWinSetBusy( + wWin_p w, + BOOL_T busy ) +{ + HMENU menuH; + UINT uEnable; + int cnt, inx; + wControl_p b; + + w->isBusy = busy; + menuH = GetMenu( w->hWnd ); + if (menuH) { + uEnable = MF_BYPOSITION|(busy?MF_DISABLED:MF_ENABLED); + cnt = GetMenuItemCount(menuH); + for (inx=0; inx<cnt; inx++) + EnableMenuItem( menuH, inx, uEnable ); + } + for (b=w->first; b; b=b->next) { + if ( (b->option&BO_DISABLED)==0) { + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->setBusyProc) { + mswCallBacks[b->type]->setBusyProc( b, busy ); + } else { + if (b->hWnd) + EnableWindow( b->hWnd, (BOOL)!busy ); + } + } + } +} + + +const char * wWinGetTitle( + wWin_p w ) +{ + return w->labelStr; +} + + +void wWinClear( + wWin_p win, + wPos_t x, + wPos_t y, + wPos_t width, + wPos_t height ) +{ +} + +void wSetCursor( + wCursor_t cursor ) +{ + switch ( cursor ) { + case wCursorNormal: + case wCursorQuestion: + default: + SetCursor( LoadCursor( NULL, IDC_ARROW ) ); + break; + case wCursorWait: + SetCursor( LoadCursor( NULL, IDC_WAIT ) ); + break; + case wCursorCross: + SetCursor( LoadCursor( NULL, IDC_CROSS ) ); + break; + case wCursorIBeam: + SetCursor( LoadCursor( NULL, IDC_IBEAM ) ); + break; + } + curCursor = cursor; +} + +void wWinDoCancel( wWin_p win ) +{ + wControl_p b; + for (b=win->first; b; b=b->next) { + if ((b->type == B_BUTTON) && (b->option & BB_CANCEL) ) { + mswButtPush( b ); + } + } +} + +unsigned long wGetTimer( void ) +{ + return (unsigned long)GetTickCount(); +} + + +/* + ****************************************************************************** + * + * Control Utilities + * + ****************************************************************************** + */ + + + +void wControlSetHelp( + wControl_p b, + const char * help ) +{ + if (b->helpStr) + free(CAST_AWAY_CONST b->helpStr); + if (help) + b->helpStr = mswStrdup( help ); + else + b->helpStr = NULL; +} + + +/** + * Add control to circular list of synonymous controls. Synonymous controls are kept in sync by + * calling wControlLinkedActive for one member of the list + * + * \param IN first control + * \param IN second control + * \return none + */ + +void wControlLinkedSet( wControl_p b1, wControl_p b2 ) +{ + b2->synonym = b1->synonym; + if( b2->synonym == NULL ) + b2->synonym = b1; + + b1->synonym = b2; +} + +/** + * Activate/deactivate a group of synonymous controls. + * + * \param IN control + * \param IN state + * \return none + */ + +void wControlLinkedActive( wControl_p b, int active ) +{ + wControl_p savePtr = b; + + if( savePtr->type == B_MENUITEM ) + wMenuPushEnable( (wMenuPush_p)savePtr, active ); + else + wControlActive( savePtr, active ); + + savePtr = savePtr->synonym; + + while( savePtr && savePtr != b ) { + + if( savePtr->type == B_MENUITEM ) + wMenuPushEnable( (wMenuPush_p)savePtr, active ); + else + wControlActive( savePtr, active ); + + savePtr = savePtr->synonym; + } +} + +void wControlShow( wControl_p b, BOOL_T show ) +{ + RECT rc; + if (show) { + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->repaintProc) + mswCallBacks[b->type]->repaintProc( b->parent->hWnd, b ); + } else { + if( b->labelStr ) { + rc.left = b->labelX; + rc.right = b->x; + rc.top = b->labelY; + rc.bottom = b->labelY+b->h; + InvalidateRect( ((wControl_p)b->parent)->hWnd, &rc, TRUE ); + } + } + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->showProc) { + mswCallBacks[b->type]->showProc( b, show ); + } else { + ShowWindow( b->hWnd, show?SW_SHOW:SW_HIDE ); +#ifdef SHOW_DOES_SETFOCUS + if (show && (b->option&BO_READONLY)==0 && b->hWnd != GetFocus() ) { + hWnd = SetFocus( b->hWnd ); + } +#endif + } + b->shown = show; +} + + +void wControlSetFocus( + wControl_p b ) +{ + if ( b->hWnd ) + SetFocus( b->hWnd ); +} + + +void wControlActive( + wControl_p b, + int active ) +{ + if (active) + b->option &= ~BO_DISABLED; + else + b->option |= BO_DISABLED; + if (b->parent->isBusy) + return; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->setBusyProc) { + mswCallBacks[b->type]->setBusyProc( b, !active ); + } else { + EnableWindow( b->hWnd, (BOOL)active ); + InvalidateRect( b->hWnd, NULL, TRUE ); + } +} + + +const char * wControlGetHelp( wControl_p b ) +{ + return b->helpStr; +} + + +wPos_t wLabelWidth( const char * labelStr ) +{ + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( mswHWnd ); + lab_l = strlen(labelStr); + LABELFONTSELECT + dw = GetTextExtent( hDc, CAST_AWAY_CONST labelStr, lab_l ); + LABELFONTRESET + ReleaseDC( mswHWnd, hDc ); + return LOWORD(dw) + 5; +} + + +wPos_t wControlGetWidth( + wControl_p b) /* Control */ +{ + return b->w; +} + + +wPos_t wControlGetHeight( + wControl_p b) /* Control */ +{ + return b->h; +} + + +wPos_t wControlGetPosX( + wControl_p b) /* Control */ +{ + return b->x; +} + + +wPos_t wControlGetPosY( + wControl_p b) /* Control */ +{ + return b->y; +} + + +void wControlSetPos( + wControl_p b, + wPos_t x, + wPos_t y ) +{ + b->labelX = x; + b->labelY = y+2; + + if (b->labelStr) { + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( b->parent->hWnd ); + LABELFONTSELECT + lab_l = strlen(b->labelStr); + dw = GetTextExtent( hDc, CAST_AWAY_CONST b->labelStr, lab_l ); + b->labelX -= LOWORD(dw) + 5; + LABELFONTRESET + ReleaseDC( b->parent->hWnd, hDc ); + } + + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->setPosProc) { + mswCallBacks[b->type]->setPosProc( b, x, y ); + } else { + b->x = x; + b->y = y; + if (b->hWnd) + if (!SetWindowPos( b->hWnd, HWND_TOP, x, y, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("wControlSetPos"); + } +} + + +void wControlSetLabel( + wControl_p b, + const char * labelStr ) +{ + if ( b->type == B_RADIO || b->type == B_TOGGLE ) { + ; + } else { + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( b->parent->hWnd ); + lab_l = strlen(labelStr); + LABELFONTSELECT + dw = GetTextExtent( hDc, CAST_AWAY_CONST labelStr, lab_l ); + LABELFONTRESET + b->labelX = b->x - LOWORD(dw) - 5; + ReleaseDC( b->parent->hWnd, hDc ); + b->labelStr = mswStrdup( labelStr ); + if (b->type == B_BUTTON) + SetWindowText( b->hWnd, labelStr ); + } +} + + +void wControlSetContext( + wControl_p b, + void * context ) +{ + b->data = context; +} + +static int controlHiliteWidth = 5; +static int controlHiliteWidth2 = 3; +void wControlHilite( + wControl_p b, + wBool_t hilite ) +{ + HDC hDc; + HPEN oldPen, newPen; + int oldMode; + + if ( b == NULL ) return; + if ( !IsWindowVisible(b->parent->hWnd) ) return; + if ( !IsWindowVisible(b->hWnd) ) return; + hDc = GetDC( b->parent->hWnd ); + newPen = CreatePen( PS_SOLID, controlHiliteWidth, RGB(0,0,0) ); + 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 ); + SetROP2( hDc, oldMode ); + SelectObject( hDc, oldPen ); + DeleteObject( newPen ); + ReleaseDC( b->parent->hWnd, hDc ); +} + +/* + ***************************************************************************** + * + * Exported Utility Functions + * + ***************************************************************************** + */ + + +void wMessage( + wWin_p w, + const char * msg, + int beep ) +{ + HDC hDc; + int oldRop; + POS_T h; + RECT rect; + LABELFONTDECL + + if (beep) + MessageBeep(0); + GetClientRect( w->hWnd, &rect ); + hDc = GetDC( w->hWnd ); + oldRop = SetROP2( hDc, R2_WHITE ); + h = w->h+2; + Rectangle( hDc, 0, h, w->w, h ); + SetROP2( hDc, oldRop ); + LABELFONTSELECT + TextOut( hDc, 0, h, msg, strlen(msg) ); + LABELFONTRESET + ReleaseDC( w->hWnd, hDc ); +} + + +void wExit( int rc ) +{ + INDEX_T inx; + wControl_p b; + + mswPutCustomColors(); + wPrefFlush(); + for ( inx=controlMap_da.cnt-1; inx>=0; inx-- ) { + b = controlMap(inx).b; + if (b != NULL) { + if (b->type == W_MAIN || b->type == W_POPUP) { + wWin_p w = (wWin_p)b; + savePos( w ); + if (w->winProc != NULL) + w->winProc( w, wQuit_e, w->data ); + } + } + } + for ( inx=controlMap_da.cnt-1; inx>=0; inx-- ) { + b = controlMap(inx).b; + if (b != NULL) { + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->doneProc != NULL) + mswCallBacks[b->type]->doneProc( b ); + } + controlMap(inx).b = NULL; + } + deleteBitmaps(); + if (mswOldTextFont != (HFONT)0) + DeleteObject( mswOldTextFont ); + if (helpInitted) { + WinHelp(mswHWnd, helpFile, HELP_QUIT, 0L ); + helpInitted = FALSE; + } + if (balloonHelpHWnd) { + HDC hDc; + hDc = GetDC( balloonHelpHWnd ); + SelectObject( hDc, balloonHelpOldFont ); + DeleteObject( balloonHelpNewFont ); + ReleaseDC( balloonHelpHWnd, hDc ); + } +#ifdef HELPSTR + fclose( helpStrF ); +#endif + DestroyWindow( mswHWnd ); + if (mswPalette) { + DeleteObject( mswPalette ); + /*DeleteObject( mswPrintPalette );*/ + } +} + + +void wFlush( + void ) +{ + wWin_p win; + + inMainWndProc = FALSE; + mswRepaintAll(); + for (win=winFirst; win; win=(wWin_p)win->next) + UpdateWindow( win->hWnd ); +} + +void wUpdate( + wWin_p win ) +{ + UpdateWindow( win->hWnd ); +} + +static wBool_t paused; +static wAlarmCallBack_p alarmFunc; +static setTriggerCallback_p triggerFunc; +static wControl_p triggerControl; + +/** + * Wait until the pause timer expires. During that time, the message loop is + * handled and queued messages are processed + */ + +static void pausedLoop( void ) +{ + MSG msg; + while (paused && GetMessage( &msg, NULL, 0, 0 )) { + if ( (mswWin) && (!mswTranslateAccelerator( mswWin->hWnd, &msg )) ) { + TranslateMessage( &msg ); + } + DispatchMessage( &msg ); + } +} + +/** + * Timer callback function for the pause timer. The only purpose of this + * timer proc is to clear the waiting flag and kill the timer itself. + */ +void CALLBACK TimerProc( HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ) +{ + if (idEvent == PAUSE_TIMER) { + paused = FALSE; + KillTimer( hWnd, PAUSE_TIMER ); + } +} + +/** + * Pause the application for a specified time. + */ + +void wPause( long msec ) +{ + paused = TRUE; + if (msec > 65000L) + msec = 65000L; + pauseTimer = SetTimer( mswHWnd, PAUSE_TIMER, (UINT)msec, TimerProc ); + if (pauseTimer == 0) + mswFail("wPause: No timers"); + else + pausedLoop(); +} + + +void wAlarm( + long msec, + wAlarmCallBack_p func ) +{ + alarmFunc = func; + if (msec > 65000L) + msec = 65000L; + alarmTimer = SetTimer( mswHWnd, ALARM_TIMER, (UINT)msec, NULL ); + if (alarmTimer == 0) + mswFail("wAlarm: No timers"); +} + + +void mswSetTrigger( + wControl_p control, + setTriggerCallback_p func ) +{ + UINT msec = (UINT)500; + triggerControl = control; + triggerFunc = func; + if (func == NULL && triggerTimer != 0) { + KillTimer( mswHWnd, triggerTimer ); + triggerTimer = 0; + return; + } + if (msec > 65000L) + msec = 65000L; + triggerTimer = SetTimer( mswHWnd, TRIGGER_TIMER, (UINT)msec, NULL ); + if (triggerTimer == 0) + mswFail("wAlarm: No timers"); +} + + +void wBeep( void ) +{ + MessageBeep( MB_OK ); +} + +/** + * Show a notification window with a yes/no reply and an icon. + * + * \param type IN type of message: Information, Warning, Error + * \param msg IN message to display + * \param yes IN text for accept button + * \param no IN text for cancel button + * \return True when accept was selected, false otherwise + */ + +int wNoticeEx( + int type, + const char * msg, + const char * yes, + const char * no ) +{ + int res; + UINT flag; + char *headline; + + switch( type ) { + case NT_INFORMATION: + flag = MB_ICONINFORMATION; + headline = _("Information"); + break; + case NT_WARNING: + flag = MB_ICONWARNING; + headline = _("Warning"); + break; + case NT_ERROR: + flag = MB_ICONERROR; + headline = _("Error"); + break; + } + res = MessageBox( mswHWnd, msg, headline, flag | MB_TASKMODAL|((no==NULL)?MB_OK:MB_YESNO) ); + return res == IDOK || res == IDYES; +} + +int wNotice( + const char * msg, + const char * yes, + const char * no ) +{ + int res; + res = MessageBox( mswHWnd, msg, "Notice", MB_TASKMODAL|((no==NULL)?MB_OK:MB_YESNO) ); + return res == IDOK || res == IDYES; +} + +/** + * Show a notification window with three choices and an icon. + * + * \param msg IN message to display + * \param yes IN text for yes button + * \param no IN text for no button + * \param cancel IN text for cancel button + * \return 1 for yes, -1 for no, 0 for cancel + */ + + +int wNotice3( + const char * msg, + const char * yes, + const char * no, + const char * cancel ) +{ + int res; + res = MessageBox( mswHWnd, msg, _("Warning"), MB_ICONWARNING | MB_TASKMODAL|MB_YESNOCANCEL ); + if ( res == IDOK || res == IDYES ) + return 1; + else if ( res == IDNO ) + return -1; + else + return 0; +} + + +void wHelp( + const char * topic ) +{ + char *pszHelpTopic; + HWND hwndHelp; + + if (!helpInitted) { + HtmlHelp( NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie) ; + helpInitted = TRUE; + } +/* "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 ); + assert( pszHelpTopic != NULL ); + + sprintf( pszHelpTopic, "/%s.html", topic ); + hwndHelp = HtmlHelp(mswHWnd, helpFile, HH_DISPLAY_TOPIC, (DWORD_PTR)pszHelpTopic); + if( !hwndHelp ) + wNoticeEx( NT_ERROR, pszHelpTopic, "Ok", NULL ); + + free( pszHelpTopic ); +} + + +void doHelpMenu( void * context ) +{ + HH_FTS_QUERY ftsQuery; + + if( !helpInitted ) { + HtmlHelp( NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie) ; + helpInitted = TRUE; + } + + switch ((int)(long)context) { + case 1: /* Contents */ + HtmlHelp( mswHWnd, helpFile, HH_DISPLAY_TOC, (DWORD_PTR)NULL ); + break; + case 2: /* Search */ + ftsQuery.cbStruct = sizeof( ftsQuery ); + ftsQuery.fExecute = FALSE; + ftsQuery.fStemmedSearch = FALSE; + ftsQuery.fTitleOnly = FALSE; + ftsQuery.pszSearchQuery = NULL; + ftsQuery.pszWindow = NULL; + + HtmlHelp( mswHWnd, helpFile, HH_DISPLAY_SEARCH,(DWORD)&ftsQuery ); + break; + default: + return; + } + helpInitted = TRUE; +} + +void wMenuAddHelp( + wMenu_p m ) +{ + wMenuPushCreate( m, NULL, "&Contents", 0, doHelpMenu, (void*)1 ); + wMenuPushCreate( m, NULL, "&Search for Help on...", 0, doHelpMenu, (void*)2 ); +} + + +void wSetBalloonHelp( wBalloonHelp_t * bh ) +{ + balloonHelpStrings = bh; +} + + +void wEnableBalloonHelp( int enable ) +{ + balloonHelpEnable = enable; +} + + +void wBalloonHelpUpdate ( void ) +{ +} + + +void wControlSetBalloonText( wControl_p b, const char * text ) +{ + b->tipStr = mswStrdup( text ); +} + + +void startBalloonHelp( void ) +{ + HDC hDc; + DWORD extent; + int w, h; + RECT rect; + POINT pt; + wBalloonHelp_t * bh; + const char * hs; + HFONT hFont; + + if (!balloonHelpStrings) + return; + if (!balloonHelpEnable) + return; + if (balloonHelpHWnd) { + if ( balloonHelpButton->tipStr ) { + hs = balloonHelpButton->tipStr; + } else { + hs = balloonHelpButton->helpStr; + if (!hs) + return; + for ( bh = balloonHelpStrings; bh->name && strcmp(bh->name,hs) != 0; bh++ ); + if (!bh->name || !bh->value) + return; + balloonHelpButton->tipStr = hs = bh->value; + } +if (newHelp) { + wControlSetBalloon( balloonHelpButton, 0, 0, hs ); +} else { + hDc = GetDC( balloonHelpHWnd ); + hFont = SelectObject( hDc, mswLabelFont ); + extent = GetTextExtent( hDc, CAST_AWAY_CONST hs, strlen(hs) ); + w = LOWORD( extent ); + h = HIWORD( extent ); + pt.x = 0; + if ( balloonHelpButton->type == B_RADIO || + balloonHelpButton->type == B_TOGGLE ) { + pt.y = balloonHelpButton->h; + } else { + GetClientRect( balloonHelpButton->hWnd, &rect ); + pt.y = rect.bottom; + } + ClientToScreen( balloonHelpButton->hWnd, &pt ); + if (pt.x + w+2 > screenWidth) + pt.x = screenWidth-(w+2); + if (pt.x < 0) + pt.x = 0; + SetWindowPos( balloonHelpHWnd, HWND_TOPMOST, pt.x, pt.y, w+6, h+4, + SWP_SHOWWINDOW|SWP_NOACTIVATE ); + SetBkColor( hDc, GetSysColor( COLOR_INFOBK )); + TextOut( hDc, 2, 1, hs, strlen(hs) ); + SelectObject( hDc, hFont ); + ReleaseDC( balloonHelpHWnd, hDc ); +} + } +} + +void closeBalloonHelp( void ) +{ + if (balloonHelpTimer) { + KillTimer( mswHWnd, balloonHelpTimer ); + balloonHelpTimer = 0; + } + if (balloonHelpState == balloonHelpShow) + if (balloonHelpHWnd) + ShowWindow( balloonHelpHWnd, SW_HIDE ); + balloonHelpState = balloonHelpIdle; +} + + +void wControlSetBalloon( wControl_p b, wPos_t dx, wPos_t dy, const char * msg ) +{ + HDC hDc; + DWORD extent; + int w, h; + RECT rect; + POINT pt; + HFONT hFont; + + if ( msg ) { + hDc = GetDC( balloonHelpHWnd ); + hFont = SelectObject( hDc, mswLabelFont ); + extent = GetTextExtent( hDc, CAST_AWAY_CONST msg, strlen(msg) ); + w = LOWORD( extent ); + h = HIWORD( extent ); + if ( b->type == B_RADIO || + b->type == B_TOGGLE ) { + pt.y = b->h; + } else { + GetClientRect( b->hWnd, &rect ); + pt.y = rect.bottom; + } + pt.x = dx; + pt.y -= dy; + ClientToScreen( b->hWnd, &pt ); + if (pt.x + w+2 > screenWidth) + pt.x = screenWidth-(w+2); + if (pt.x < 0) + pt.x = 0; + SetWindowPos( balloonHelpHWnd, HWND_TOPMOST, pt.x, pt.y, w+6, h+4, + SWP_SHOWWINDOW|SWP_NOACTIVATE ); + SetBkColor( hDc, GetSysColor( COLOR_INFOBK ) ); + TextOut( hDc, 2, 1, msg, strlen(msg) ); + SelectObject( hDc, hFont ); + ReleaseDC( balloonHelpHWnd, hDc ); + + balloonHelpState = balloonHelpShow; + balloonControlButton = b; + } else { + closeBalloonHelp(); + } +} + + +int wGetKeyState( void ) +{ + int rc, keyState; + rc = 0; + keyState = GetAsyncKeyState( VK_SHIFT ); + if (keyState & 0x8000) + rc |= WKEY_SHIFT; + keyState = GetAsyncKeyState( VK_CONTROL ); + if (keyState & 0x8000) + rc |= WKEY_CTRL; + keyState = GetAsyncKeyState( VK_MENU ); + if (keyState & 0x8000) + rc |= WKEY_ALT; + return rc; +} + + +/* + ****************************************************************************** + * + * File Selection + * + ****************************************************************************** + */ + +FILE * wFileOpen( + const char * fileName, + const char * mode ) +{ + return fopen( fileName, mode ); +} + + +struct wFilSel_t { + wWin_p parent; + wFilSelMode_e mode; + int option; + const char * title; + char * extList; + wFilSelCallBack_p action; + void * data; + }; + +static char selFileName[1024]; +static char selFileTitle[1024]; +static char sysDirName[1024]; + +int wFilSelect( + struct wFilSel_t * fs, + const char * dirName ) +{ + int rc; + OPENFILENAME ofn; + char * fileName; + const char * ext; + char defExt[4]; + int i; + + if (dirName == NULL || + dirName[0] == '\0' || + strcmp(dirName, ".") == 0 ) { + GetSystemDirectory( CAST_AWAY_CONST (dirName = sysDirName), sizeof sysDirName ); + } + memset( &ofn, 0, sizeof ofn ); + ofn.lStructSize = sizeof ofn; + ofn.hwndOwner = mswHWnd; + ofn.lpstrFilter = fs->extList; + ofn.nFilterIndex = 0; + selFileName[0] = '\0'; + ofn.lpstrFile = selFileName; + ofn.nMaxFile = sizeof selFileName; + selFileTitle[0] = '\0'; + ofn.lpstrFileTitle = selFileTitle; + ofn.nMaxFileTitle = sizeof selFileTitle; + ofn.lpstrInitialDir = dirName; + ofn.lpstrTitle = fs->title; + ext = fs->extList + strlen(fs->extList)+1; + if (*ext++ == '*' && *ext++ == '.') { + for ( i=0; i<3 && ext[i] && ext[i]!=';'; i++ ) + defExt[i] = ext[i]; + defExt[i] = '\0'; + } else { + defExt[0] = '\0'; + } + ofn.lpstrDefExt = defExt; + ofn.Flags |= OFN_LONGFILENAMES; + if (fs->mode == FS_LOAD) { + ofn.Flags |= OFN_FILEMUSTEXIST; + rc = GetOpenFileName( &ofn ); + } else if (fs->mode == FS_SAVE) { + ofn.Flags |= OFN_OVERWRITEPROMPT; + rc = GetSaveFileName( &ofn ); + } else if (fs->mode == FS_UPDATE) { + rc = GetSaveFileName( &ofn ); + } else + return FALSE; + if (!rc) + return FALSE; + fileName = strrchr( selFileName, '\\' ); + if (fileName == NULL) { + mswFail( "wFilSelect: cant extract fileName" ); + return FALSE; + } + fs->action( selFileName, fileName+1, fs->data ); + return TRUE; +} + + +struct wFilSel_t * wFilSelCreate( + wWin_p parent, + wFilSelMode_e mode, + int option, + const char * title, + const char * extList, + wFilSelCallBack_p action, + void * data ) +{ + char * cp; + struct wFilSel_t * ret; + int len; + ret = (struct wFilSel_t*)malloc(sizeof *ret); + ret->parent = parent; + ret->mode = mode; + ret->option = option; + ret->title = mswStrdup(title); + len = strlen(extList); + ret->extList = (char*)malloc(len+2); + strcpy(ret->extList,extList); + for ( cp=ret->extList; *cp; cp++ ) { + if (*cp == '|') + *cp = '\0'; + } + *++cp = '\0'; + ret->action = action; + ret->data = data; + return ret; +} + + +const char * wMemStats( void ) +{ + int rc; + static char msg[80]; + long usedSize = 0; + long usedCnt = 0; + long freeSize = 0; + long freeCnt = 0; + _HEAPINFO heapinfo; + heapinfo._pentry = NULL; + + while ( (rc=_heapwalk( &heapinfo )) == _HEAPOK ) { + switch (heapinfo._useflag) { + case _FREEENTRY: + freeSize += (long)heapinfo._size; + freeCnt++; + break; + case _USEDENTRY: + usedSize += (long)heapinfo._size; + usedCnt++; + break; + } + } + + sprintf( msg, "Used: %ld(%ld), Free %ld(%ld)%s", + usedSize, usedCnt, freeSize, freeCnt, + (rc==_HEAPOK)?"": + (rc==_HEAPEMPTY)?"": + (rc==_HEAPBADBEGIN)?", BADBEGIN": + (rc==_HEAPEND)?"": + (rc==_HEAPBADPTR)?", BADPTR": + ", Unknown Heap Status" ); + return msg; +} + +/* + ***************************************************************************** + * + * Main + * + ***************************************************************************** + */ + +static wControl_p getControlFromCursor( HWND hWnd, wWin_p * winR ) +{ + POINT pt; + wWin_p w; + wControl_p b; + wIndex_t inx; + HWND hTopWnd; + + if (winR) + *winR = NULL; + GetCursorPos( &pt ); + hTopWnd = GetActiveWindow(); + inx = GetWindowWord( hWnd, 0 ); + if ( inx < CONTROL_BASE || inx > controlMap_da.cnt ) { + /* Unknown control */ + /*MessageBeep( MB_ICONEXCLAMATION );*/ + return NULL; + } + w=(wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + return NULL; + if (w->type != W_MAIN && w->type != W_POPUP) + return NULL; + if ( winR ) + *winR = w; + ScreenToClient( hWnd, &pt ); + for (b = w->first; b; b=b->next) { + if (b->type == B_BOX || b->type == B_LINES) + continue; + if (b->hWnd == NULL) + continue; + if (IsWindowVisible( b->hWnd ) == FALSE) + continue; + if (pt.x > b->x && pt.x < b->x+b->w && + pt.y > b->y && pt.y < b->y+b->h ) + return b; + } + return b; +} + +/** + * Window function for the main window and all popup windows. + * + */ + +LRESULT +FAR +PASCAL +MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + int inx; + wWin_p w; + wControl_p b, oldW; + int child = ((GetWindowLong( hWnd, GWL_STYLE) & WS_CHILD) != 0); + POS_T newW, newH; + RECT rect; + PAINTSTRUCT ps; + HWND hWnd2; + LRESULT ret; + HDC hDc; + wAccelKey_e extChar; + + switch (message) { + + case WM_MOUSEWHEEL: + inx = GetWindowWord( hWnd, 0 ); + b = getControlFromCursor( hWnd, NULL ); + if( b && b->type == B_DRAW ) + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) + return mswCallBacks[b->type]->messageProc( (wControl_p)b, hWnd, + message, wParam, lParam ); + return( 0 ); + 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) + break; + b = controlMap(WCMD_PARAM_ID-CONTROL_BASE).b; + if (!b) + break; + if( b->type == B_BITMAP ) { + // draw the bitmap + mswDrawIcon(((LPDRAWITEMSTRUCT)lParam)->hDC, 0, 0, (wIcon_p)(b->data), FALSE, (COLORREF)0, (COLORREF)0 ); + return( TRUE ); + } else { + mswSetFocus( b ); + ret = 0L; + if (!inMainWndProc) { + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, hWnd, message, wParam, lParam ); + } + inMainWndProc = FALSE; + } + return ret; + } + case WM_PAINT: + inx = GetWindowWord( hWnd, 0 ); + if (inx >= CONTROL_BASE && inx <= controlMap_da.cnt && + (w = (wWin_p)controlMap(inx-CONTROL_BASE).b) && + (w->type == W_MAIN || w->type == W_POPUP) && + (!IsIconic(mswHWnd)) && + (GetUpdateRect( hWnd, &rect, FALSE ) ) ) { + BeginPaint( hWnd, &ps ); + for (b=w->first; b; b=b->next ) { + if (b->shown && + mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->repaintProc) + mswCallBacks[b->type]->repaintProc( hWnd, b ); + } + EndPaint( hWnd, &ps ); + return 1L; + } + break; + + case WM_SIZE: + inx = GetWindowWord( hWnd, 0 ); + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_MAIN && w->type != W_POPUP) + break; + if (w->busy) + break; + switch( wParam ) { + case SIZE_MAXIMIZED: + case SIZE_MINIMIZED: + case SIZE_RESTORED: + newW = LOWORD( lParam ); /* WIN32?? */ + newH = HIWORD( lParam ); /* WIN32?? */ + if (newW <= 0 || newH <= 0) + break; + if (newW == w->w && newH == w->h) + break; + GetWindowRect( w->hWnd, &rect ); + GetClientRect( w->hWnd, &rect ); + InvalidateRect( w->hWnd, NULL, TRUE ); + w->w = newW; + w->h = newH; + if (w->winProc) + w->winProc( w, wResize_e, w->data ); + break; + default: + break; + } + break; + + case WM_CHAR: + case WM_KEYUP: + inx = GetWindowWord( hWnd, 0 ); + if ( inx < CONTROL_BASE || inx > controlMap_da.cnt ) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_MAIN && w->type != W_POPUP) { + if (mswCallBacks[w->type] != NULL && + mswCallBacks[w->type]->messageProc) + return mswCallBacks[w->type]->messageProc( (wControl_p)w, hWnd, + message, wParam, lParam ); + break; + } + extChar = translateExtKey( WCMD_PARAM_ID ); + if (message == WM_KEYUP ) { + if (extChar == wAccelKey_None) + break; + if (extChar == wAccelKey_Back) + break; + } + b = getControlFromCursor( hWnd, NULL ); + closeBalloonHelp(); + if (b && b->type == B_DRAW) { + return SendMessage( b->hWnd, WM_CHAR, wParam, lParam ); + } + switch (WCMD_PARAM_ID) { + case 0x0D: + /* CR - push default button */ + for (b=w->first; b; b=b->next) { + if (b->type == B_BUTTON && (b->option & BB_DEFAULT) != 0) { + inMainWndProc = TRUE; + if (mswCallBacks[B_BUTTON] != NULL && + mswCallBacks[B_BUTTON]->messageProc) { + ret = mswCallBacks[B_BUTTON]->messageProc( b, b->hWnd, + WM_COMMAND, wParam, lParam ); + } + inMainWndProc = FALSE; + break; + } + } + return 0L; + case 0x1B: + /* ESC - push cancel button */ + for (b=w->first; b; b=b->next) { + if (b->type == B_BUTTON && (b->option & BB_CANCEL) != 0) { + inMainWndProc = TRUE; + if (mswCallBacks[B_BUTTON] != NULL && + mswCallBacks[B_BUTTON]->messageProc) { + ret = mswCallBacks[B_BUTTON]->messageProc( b, b->hWnd, + WM_COMMAND, wParam, lParam ); + } + inMainWndProc = FALSE; + break; + } + } + mswSetTrigger( (wControl_p)TRIGGER_TIMER, NULL ); + return 0L; + case 0x20: + /* SPC - push current button with focus */ + if ( (b=w->focusChainNext) != NULL ) { + switch (b->type) { + case B_BUTTON: + case B_CHOICEITEM: + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, b->hWnd, + WM_COMMAND, MAKELPARAM( LOWORD(wParam), BN_CLICKED), (LPARAM)(b->hWnd) ); + } + inMainWndProc = FALSE; + break; + } + } + return 0L; + case 0x09: + /* TAB - jump to next control */ + if ( w->focusChainNext ) { + for ( b = w->focusChainNext->focusChainNext; + b!=w->focusChainNext; + b=b->focusChainNext ) { + if( IsWindowVisible(b->hWnd) && IsWindowEnabled(b->hWnd)) + break; + } + oldW = w->focusChainNext; + w->focusChainNext = b; + if (!inMainWndProc) { + inMainWndProc = TRUE; + SetFocus( b->hWnd ); +/* if( b->type == B_BUTTON) + InvalidateRect( b->hWnd, NULL, TRUE ); */ + if( oldW->type == B_BUTTON) + InvalidateRect( oldW->hWnd, NULL, TRUE ); + + inMainWndProc = FALSE; + } + } + return 0L; + } + /* Not a Draw control */ + MessageBeep( MB_ICONHAND ); + return 0L; + break; + + case WM_ENABLE: + if (wParam == 1) { /* WIN32??? */ + hWnd2 = SetFocus( hWnd ); + } + break; + + case WM_F1DOWN: + if ((hWnd2 = GetActiveWindow()) == hWnd || + (inx=GetWindowWord(hWnd2,0)) < CONTROL_BASE || inx > controlMap_da.cnt ) + return DefWindowProc( hWnd, message, wParam, lParam ); + b=controlMap(inx-CONTROL_BASE).b; + if (!b) + break; + closeBalloonHelp(); + wHelp( b->helpStr ); + return 0L; + + case WM_SETCURSOR: + /*if (any buttons down) + break;*/ + wSetCursor( curCursor ); + if (!mswAllowBalloonHelp) + break; + if (IsIconic(mswHWnd)) + break; + b = getControlFromCursor(hWnd, NULL); + if ( b == balloonControlButton ) + break; + if ( /*(!IsWindowEnabled(hWnd))*/ GetActiveWindow() != hWnd || + (!b) || b->type == B_DRAW || b->helpStr == NULL ) { + closeBalloonHelp(); + break; + } + if ( b != balloonHelpButton ) + closeBalloonHelp(); + if (balloonHelpState != balloonHelpIdle) { + break; + } + balloonHelpTimer = SetTimer( mswHWnd, BALLOONHELP_TIMER, + balloonHelpTimeOut, NULL ); + if (balloonHelpTimer == (UINT)0) + break; + balloonHelpState = balloonHelpWait; + balloonHelpButton = b; + break; + + case WM_SYSCOMMAND: + inx = GetWindowWord( hWnd, 0 ); + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_POPUP) + break; + if (w->busy) + break; + if ( (wParam&0xFFF0) != SC_CLOSE ) + break; + if (w->winProc) + w->winProc( w, wClose_e, w->data ); + wWinShow( w, FALSE ); + return 0L; + + + + case WM_CLOSE: + inx = GetWindowWord( hWnd, 0 ); + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type == W_MAIN) { + /* It's the big one! */ + /* call main window procedure for processing of shutdown */ + if( w->winProc ) + (w->winProc( w, wClose_e, NULL )); + return 0L; + } + + case WM_DESTROY: + if ( hWnd == mswHWnd ) { + PostQuitMessage(0L); + return 0L; + } + break; + + case WM_TIMER: + if (wParam == ALARM_TIMER) { + KillTimer( mswHWnd, alarmTimer ); + alarmFunc(); + } else if (wParam == TRIGGER_TIMER) { + KillTimer( mswHWnd, triggerTimer ); + triggerTimer = 0; + if (triggerFunc) + triggerFunc( triggerControl ); + } else if (wParam == BALLOONHELP_TIMER) { + KillTimer( hWnd, balloonHelpTimer ); + balloonHelpTimer = (UINT)0; + startBalloonHelp(); + } + return 0L; + + case WM_MENUSELECT: + mswAllowBalloonHelp = TRUE; + closeBalloonHelp(); + break; + + case WM_WINDOWPOSCHANGED: + if (hWnd == mswHWnd && !IsIconic(hWnd) && needToDoPendingShow) { + for (w=winFirst; w; w=(wWin_p)w->next) { + if (w->hWnd != mswHWnd && + w->pendingShow ) + ShowWindow( w->hWnd, SW_SHOW ); + w->pendingShow = FALSE; + } + needToDoPendingShow = FALSE; + } + break; + + case 51: + count51++; + /*return NULL;*/ + +#ifdef LATER + case WM_SETFOCUS: + hDc = GetDC( hWnd ); + rc = RealizePalette( hDc ); + ReleaseDC( hWnd, hDc ); + inx = GetWindowWord( hWnd, 0 ); + if ( inx < CONTROL_BASE || inx > controlMap_da.cnt ) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_MAIN && w->type != W_POPUP) + break; + for (b=w->first; b; b=b->next) { + if (b->hWnd && (b->type == B_BUTTON || b->type==B_DRAW)) { + hDc = GetDC( b->hWnd ); + rc = RealizePalette( hDc ); + ReleaseDC( b->hWnd, hDc ); + } + } + break; +#endif + + case WM_PALETTECHANGED: + if (wParam == (WPARAM)hWnd) + return 0L; + + case WM_QUERYNEWPALETTE: + if (mswPalette) { + hDc = GetDC( hWnd ); + SelectPalette( hDc, mswPalette, 0 ); + inx = RealizePalette( hDc ); + ReleaseDC( hWnd, hDc ); + if (inx>0) + InvalidateRect( hWnd, NULL, TRUE ); + return inx; + } + + case WM_ACTIVATE: + if ( LOWORD(wParam) == WA_INACTIVE ) + closeBalloonHelp(); + break; + + case WM_HSCROLL: + case WM_VSCROLL: + b = getControlFromCursor( hWnd, NULL ); + if (!b) + break; + /*mswSetFocus( b );*/ + ret = 0L; + if (!inMainWndProc) { + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, hWnd, message, wParam, lParam ); + } + inMainWndProc = FALSE; + } + return ret; + + case WM_LBUTTONDOWN: + case WM_MOUSEMOVE: + case WM_LBUTTONUP: + b = getControlFromCursor( hWnd, NULL ); + if (!b) + break; + /*mswSetFocus( b );*/ + ret = 0L; + if (!inMainWndProc) { + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, hWnd, message, wParam, lParam ); + } + inMainWndProc = FALSE; + } + return ret; + + default: + ; + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + +/* + ***************************************************************************** + * + * INIT + * + ***************************************************************************** + */ + +/** + * Register window classes used by the application. These are the main window, + * the popup windows, the tooltip window and the drawing area. + * + * \param hinstCurrent IN application instance + * \return FALSE in case of error, else TRUE + */ + +static BOOL InitApplication( HINSTANCE hinstCurrent ) +{ + WNDCLASS wc; + + wc.style = 0L; + wc.lpfnWndProc = MainWndProc; + + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; + wc.hInstance = hinstCurrent; + wc.hIcon = LoadIcon( hinstCurrent, "MSWAPPICON" ); + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = "MswMainWindow"; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(MainWindow)"); + return FALSE; + } + + wc.style = CS_SAVEBITS; + wc.lpfnWndProc = MainWndProc; + + wc.cbClsExtra = 0; + wc.cbWndExtra = 8; + wc.hInstance = hinstCurrent; + wc.hIcon = LoadIcon( NULL, "wAppIcon" ); + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wc.lpszMenuName = "GenericMenu"; + wc.lpszClassName = "MswPopUpWindow"; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(PopUpWindow)"); + return FALSE; + } + + wc.style = CS_SAVEBITS; + wc.lpfnWndProc = DefWindowProc; + + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; + wc.hInstance = hinstCurrent; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = CreateSolidBrush( GetSysColor( COLOR_INFOBK ) ); + wc.lpszMenuName = NULL; + wc.lpszClassName = "MswBalloonHelp"; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(BalloonHelp)"); + return FALSE; + } + + wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; + wc.lpfnWndProc = mswDrawPush; + wc.lpszClassName = mswDrawWindowClassName; + wc.cbWndExtra = 4; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(drawClass)"); + return FALSE; + } + return TRUE; +} + +/** + * Standard entry point for the app. Nothing special, + * create some window classes, initialize some global + * variables with system information, call the application main + * and finally process the message queue. + */ + +int PASCAL WinMain( HINSTANCE hinstCurrent, HINSTANCE hinstPrevious, LPSTR lpszCmdLine, int nCmdShow ) +{ + MSG msg; + HDC hDc; + char **argv; + int argc; + TEXTMETRIC tm; + DWORD dw; + + if (!hinstPrevious) + if (!InitApplication(hinstCurrent)) + return FALSE; + + mswHInst = hinstCurrent; + + mTitleH = GetSystemMetrics( SM_CYCAPTION ) - 1; + mFixBorderW = GetSystemMetrics( SM_CXBORDER ); + mFixBorderH = GetSystemMetrics( SM_CYBORDER ); + mResizeBorderW = GetSystemMetrics( SM_CXFRAME ); + mResizeBorderH = GetSystemMetrics( SM_CYFRAME ); + mMenuH = GetSystemMetrics( SM_CYMENU ) + 1; + screenWidth = GetSystemMetrics( SM_CXSCREEN ); + screenHeight = GetSystemMetrics( SM_CYSCREEN ); + mswLabelFont = GetStockObject( DEFAULT_GUI_FONT ); + + hDc = GetDC( 0 ); + mswScale = GetDeviceCaps( hDc, LOGPIXELSX ) / 96.0; + if ( mswScale < 1.0 ) + mswScale = 1.0; + GetTextMetrics( hDc, &tm ); + mswEditHeight = tm.tmHeight + 8; + dw = GetTextExtent( hDc, "AXqypj", 6 ); + mswEditHeight = HIWORD(dw)+2; + ReleaseDC( 0, hDc ); + + mswCreateCheckBitmaps(); + + /* + get the command line parameters in standard C style and pass them to the main function. The + globals are predefined by Visual C + */ + argc = __argc; + argv = __argv; + + mswWin = wMain( argc, (char**)argv ); + if (mswWin == NULL) + return 0; + + balloonHelpHWnd = CreateWindow( "MswBalloonHelp", "BalloonHelp", + WS_POPUP|WS_BORDER, + 0, 0, 80, 40, mswHWnd, NULL, mswHInst, NULL ); + if (balloonHelpHWnd == (HWND)0) { + mswFail( "CreateWindow(BALLOONHELP)" ); + } else { + hDc = GetDC( balloonHelpHWnd ); + /* We need to remember this because the hDc gets changed somehow, + /* and we when we select the oldFont back in we don't get newFont */ + balloonHelpNewFont = CreateFont( - balloonHelpFontSize, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, balloonHelpFaceName ); + balloonHelpOldFont = SelectObject( hDc, balloonHelpNewFont ); + ReleaseDC( balloonHelpHWnd, hDc ); + } + + SetCursor( LoadCursor( NULL, IDC_ARROW ) ); + while (GetMessage( &msg, NULL, 0, 0 )) { + if (!mswTranslateAccelerator( mswWin->hWnd, &msg )) { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } + + if( helpInitted == TRUE ) + HtmlHelp( NULL, NULL, HH_UNINITIALIZE, (DWORD)dwCookie); + + return msg.wParam; +} diff --git a/app/wlib/mswlib/mswmsg.c b/app/wlib/mswlib/mswmsg.c new file mode 100644 index 0000000..b128534 --- /dev/null +++ b/app/wlib/mswlib/mswmsg.c @@ -0,0 +1,212 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Message Boxes + * + ***************************************************************************** + */ + +/** + * factors by which fonts are resized if nonstandard text height is used + */ + +#define SCALE_LARGE 1.6 +#define SCALE_SMALL 0.8 + +#ifdef CONTROL3D +static int messageHeight = 18; +#endif + +struct wMessage_t { + WOBJ_COMMON + long flags; + const char * message; + }; + +#ifndef CONTROL3D +static void repaintMessage( + HWND hWnd, + wControl_p b ) +{ + wMessage_p bm = (wMessage_p)b; + HDC hDc; + RECT rect; + HFONT hFont; + LOGFONT msgFont; + double scale = 1.0; + + hDc = GetDC( hWnd ); + + if ( !mswThickFont ) + hFont = SelectObject( hDc, mswLabelFont ); + + switch( wMessageSetFont( ((wMessage_p)b)->flags )) + { + case BM_LARGE: + scale = SCALE_LARGE; + break; + case BM_SMALL: + scale = SCALE_SMALL; + break; + } + + /* is a non-standard text height required? */ + if( scale != 1.0 ) + { + /* if yes, get information about the standard font used */ + GetObject( GetStockObject( DEFAULT_GUI_FONT ), sizeof( LOGFONT ), &msgFont ); + + /* change the height */ + msgFont.lfHeight = (long)((double)msgFont.lfHeight * scale); + + /* create and activate the new font */ + hFont = SelectObject( hDc, CreateFontIndirect( &msgFont ) ); + } else { + if ( !mswThickFont ) + hFont = SelectObject( hDc, mswLabelFont ); + } + + rect.bottom = (long)(bm->y+( bm->h )); + rect.right = (long)(bm->x+( scale * bm->w )); + rect.top = bm->y; + 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 ); + + if( scale != 1.0 ) + /* in case we did create a new font earlier, delete it now */ + DeleteObject( SelectObject( hDc, GetStockObject( DEFAULT_GUI_FONT ))); + else + if ( !mswThickFont ) + SelectObject( hDc, hFont ); + + ReleaseDC( hWnd, hDc ); +} +#endif + +void wMessageSetValue( + wMessage_p b, + const char * arg ) +{ + if (b->message) + free( CAST_AWAY_CONST b->message ); + if (arg) + b->message = mswStrdup( arg ); + else + b->message = NULL; +#ifdef CONTROL3D + SetWindowText( b->hWnd, arg ); +#else + repaintMessage( ((wControl_p)(b->parent))->hWnd, (wControl_p)b ); +#endif +} + +void wMessageSetWidth( + wMessage_p b, + wPos_t width ) +{ + b->w = width; +#ifdef CONTROL3D + SetWindowPos( b->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + width, messageHeight, SWP_NOMOVE ); +#endif +} + + +wPos_t wMessageGetHeight( long flags ) +{ +#ifdef CONTROL3D + return messageHeight; +#else + double scale = 1.0; + + if( flags & BM_LARGE ) + scale = SCALE_LARGE; + if( flags & BM_SMALL ) + scale = SCALE_SMALL; + + return((wPos_t)((mswEditHeight - 4) * scale )); +#endif +} + +static void mswMessageSetBusy( + wControl_p b, + BOOL_T busy ) +{ +} + + +#ifndef CONTROL3D +static callBacks_t messageCallBacks = { + repaintMessage, + NULL, + NULL, + mswMessageSetBusy }; +#endif + + +wMessage_p wMessageCreateEx( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + POS_T width, + const char *message, + long flags ) +{ + wMessage_p b; + int index; + +#ifdef CONTROL3D + RECT rect; +#endif + + b = (wMessage_p)mswAlloc( parent, B_MESSAGE, NULL, sizeof *b, NULL, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option |= BO_READONLY; + b->message = mswStrdup( message ); + b->flags = flags; + +#ifdef CONTROL3D + if ( width <= 0 && strlen(b->message) > 0 ) { + width = wLabelWidth( b->message ); + } + + b->hWnd = CreateWindow( "STATIC", NULL, + SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE, + b->x, b->y, + width, messageHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(MESSAGE)"); + return b; + } + + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + SetWindowText( b->hWnd, message ); + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; +#else + b->w = width; + b->h = wMessageGetHeight( flags ) + 1; + + repaintMessage( ((wControl_p)parent)->hWnd, (wControl_p)b ); +#endif + mswAddButton( (wControl_p)b, FALSE, helpStr ); +#ifndef CONTROL3D + mswCallBacks[B_MESSAGE] = &messageCallBacks; +#endif + return b; +} diff --git a/app/wlib/mswlib/mswpref.c b/app/wlib/mswlib/mswpref.c new file mode 100644 index 0000000..90cf8fc --- /dev/null +++ b/app/wlib/mswlib/mswpref.c @@ -0,0 +1,274 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <stdio.h> +#include "mswint.h" +#include <shlobj.h> +#include <Shlwapi.h> + +#if _MSC_VER >=1400 + #define stricmp _stricmp +#endif + +char * mswStrdup( const char * ); +static char appLibDirName[MAX_PATH]; +static char appWorkDirName[MAX_PATH]; + +/** + * Get the location of the shared files (parameters, help file, etc. ): This location is + * derived from the modulename, ie. the directory where the exe is installed. + * For an instalaltion directory of somedir/bin/xtrkcad.exe the library directory is + * somedir/share/xtrkcad/ + */ + +const char * wGetAppLibDir( void ) +{ + char *cp; + char module_name[MAX_PATH]; + + if (appLibDirName[0] != '\0') { + return appLibDirName; + } + + GetModuleFileName( mswHInst, module_name, sizeof module_name ); + cp = strrchr( module_name, '\\' ); + if (cp) + *cp = '\0'; + +#ifdef XTRKCAD_CMAKE_BUILD + strcpy(appLibDirName, module_name); + strcat(appLibDirName, "\\..\\share\\xtrkcad"); + _fullpath( appLibDirName, appLibDirName, MAX_PATH ); + return appLibDirName; +#endif + + strcpy(appLibDirName, module_name); + return appLibDirName; +} + + +/** + * Gets the working directory for the application. At least the INI file is stored here. + * The working directory can be specified manually by creating a file called xtrkcad0.ini + * in the application lib dir (the directory where the .EXE is located). + * + * [workdir] + * path=somepath + * + * when somepath is set to the keyword "installdir", the install directory for the EXE is + * used. + * + * If no xtrkcad0.ini could be found, the user settings directory (appdata) is used. + * + */ +const char * wGetAppWorkDir( void ) +{ + char *cp; + int rc; + if ( appWorkDirName[0] != 0 ) { + return appWorkDirName; + } + wGetAppLibDir(); + sprintf( mswTmpBuff, "%s\\xtrkcad0.ini", appLibDirName ); + rc = GetPrivateProfileString( "workdir", "path", "", appWorkDirName, sizeof appWorkDirName, mswTmpBuff ); + if ( rc!=0 ) { + if ( stricmp( appWorkDirName, "installdir" ) == 0 ) { + strcpy( appWorkDirName, appLibDirName ); + } else { + cp = &appWorkDirName[strlen(appWorkDirName)-1]; + while (cp>appWorkDirName && *cp == '\\') *cp-- = 0; + } + return appWorkDirName; + } + + if (SHGetSpecialFolderPath( NULL, mswTmpBuff, CSIDL_APPDATA, 0 ) == 0 ) { + wNoticeEx( NT_ERROR, "Cannot get user's profile directory", "Exit", NULL ); + wExit(0); + } else { + sprintf( appWorkDirName, "%s\\%s", mswTmpBuff, "XTrackCad" ); + if( !PathIsDirectory( appWorkDirName )) { + if( !CreateDirectory( appWorkDirName, NULL )) { + wNoticeEx( NT_ERROR, "Cannot create user's profile directory", "Exit", NULL ); + wExit(0); + } + } + } + + return appWorkDirName; +} + +/** Get the user's home directory. The environment variable HOME is + * assumed to contain the proper directory. + * + * \return pointer to the user's home directory + */ + +const char *wGetUserHomeDir( void ) +{ + if (SHGetSpecialFolderPath( NULL, mswTmpBuff, CSIDL_PERSONAL, 0 ) == 0 ) { + wNoticeEx( NT_ERROR, "Cannot get user's home directory", "Exit", NULL ); + wExit(0); + return( NULL ); + } else { + return( mswTmpBuff ); + } +} + +typedef struct { + char * section; + char * name; + BOOL_T present; + BOOL_T dirty; + char * val; + } prefs_t; +dynArr_t prefs_da; +#define prefs(N) DYNARR_N(prefs_t,prefs_da,N) + +void wPrefSetString( const char * section, const char * name, const char * sval ) +{ + prefs_t * p; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if ( strcmp( p->section, section ) == 0 && strcmp( p->name, name ) == 0 ) { + if (p->val) + free(p->val); + p->dirty = TRUE; + p->val = mswStrdup( sval ); + return; + } + } + DYNARR_APPEND( prefs_t, prefs_da, 10 ); + p = &prefs(prefs_da.cnt-1); + p->name = mswStrdup(name); + p->section = mswStrdup(section); + p->dirty = TRUE; + p->val = mswStrdup(sval); +} + + +const char * wPrefGetString( const char * section, const char * name ) +{ + prefs_t * p; + int rc; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if ( strcmp( p->section, section ) == 0 && strcmp( p->name, name ) == 0 ) { + return p->val; + } + } + rc = GetPrivateProfileString( section, name, "", mswTmpBuff, sizeof mswTmpBuff, mswProfileFile ); + if (rc==0) + return NULL; + DYNARR_APPEND( prefs_t, prefs_da, 10 ); + p = &prefs(prefs_da.cnt-1); + p->name = mswStrdup(name); + p->section = mswStrdup(section); + p->dirty = FALSE; + p->val = mswStrdup(mswTmpBuff); + return p->val; +} + + +void wPrefSetInteger( const char * section, const char * name, long lval ) +{ + char tmp[20]; + + sprintf( tmp, "%ld", lval ); + wPrefSetString( section, name, tmp ); +} + + +wBool_t wPrefGetInteger( + const char * section, + const char * name, + long *res, + long def ) +{ + const char * cp; + char * cp1; + + cp = wPrefGetString( section, name ); + if (cp == NULL) { + *res = def; + return FALSE; + } + *res = strtol(cp,&cp1,0); + if (cp==cp1) { + *res = def; + return FALSE; + } + return TRUE; +} + + +void wPrefSetFloat( + const char * section, /* Section */ + const char * name, /* Name */ + double lval ) /* Value */ +/* +*/ +{ + char tmp[20]; + + sprintf(tmp, "%0.6f", lval ); + wPrefSetString( section, name, tmp ); +} + + +wBool_t wPrefGetFloat( + const char * section, /* Section */ + const char * name, /* Name */ + double * res, /* Address of result */ + double def ) /* Default value */ +/* +*/ +{ + const char * cp; + char * cp1; + + cp = wPrefGetString( section, name ); + if (cp == NULL) { + *res = def; + return FALSE; + } + *res = strtod(cp, &cp1); + if (cp == cp1) { + *res = def; + return FALSE; + } + return TRUE; +} + + +void wPrefFlush( void ) +{ + prefs_t * p; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if ( p->dirty ) + WritePrivateProfileString( p->section, p->name, p->val, mswProfileFile ); + } + WritePrivateProfileString( NULL, NULL, NULL, mswProfileFile ); +} + + +void wPrefReset( + void ) +/* +*/ +{ + prefs_t * p; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if (p->section) + free( p->section ); + if (p->name) + free( p->name ); + if (p->val) + free( p->val ); + } + prefs_da.cnt = 0; +} diff --git a/app/wlib/mswlib/mswprint.c b/app/wlib/mswlib/mswprint.c new file mode 100644 index 0000000..91f05ea --- /dev/null +++ b/app/wlib/mswlib/mswprint.c @@ -0,0 +1,387 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#ifndef WIN32 +#include <print.h> +#endif +#include "mswint.h" + +/* + ***************************************************************************** + * + * PRINT + * + ***************************************************************************** + */ + + +struct wDraw_t print_d; + +#ifdef WIN32 +struct tagPDA printDlg; +#else +struct tagPD printDlg; +#endif +static int printStatus = FALSE; +static DOCINFO docInfo; +static double pageSizeW = 8.5, pageSizeH = 11.0; +static double physSizeW = 8.5, physSizeH = 11.0; +static int pageCount = -1; + +static HPALETTE newPrintPalette; +static HPALETTE oldPrintPalette; + + +void wPrintClip( wPos_t x, wPos_t y, wPos_t w, wPos_t h ) +{ + wDrawClip( &print_d, x, y, w, h ); +} + + +void getPageDim( HDC hDc ) +{ + int rc; + POINT dims; + POINT offs; + int res_w, res_h, size_w, size_h; + rc = Escape( hDc, GETPHYSPAGESIZE, 0, NULL, (LPPOINT)&dims ); + if (rc <0) { + mswFail( "GETPHYPAGESIZE" ); + } + rc = Escape( hDc, GETPRINTINGOFFSET, 0, NULL, (LPPOINT)&offs ); + if (rc <0) { + mswFail( "GETPRINTINGOFFSET" ); + } + print_d.wFactor = (double)GetDeviceCaps( hDc, LOGPIXELSX ); + print_d.hFactor = (double)GetDeviceCaps( hDc, LOGPIXELSY ); + if (print_d.wFactor <= 0 || print_d.hFactor <= 0) { + mswFail( "getPageDim: LOGPIXELS... <= 0" ); + abort(); + } + print_d.DPI = min( print_d.wFactor, print_d.hFactor ); + size_w = GetDeviceCaps( hDc, HORZSIZE ); + size_h = GetDeviceCaps( hDc, VERTSIZE ); + print_d.w = res_w = GetDeviceCaps( hDc, HORZRES ); + print_d.h = res_h = GetDeviceCaps( hDc, VERTRES ); + 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; +} + +static wBool_t printInit( void ) +{ + static int initted = FALSE; + static int printerOk = FALSE; + if (initted) { + if (!printerOk) { + mswFail( "No Printers are defined" ); + } + return printerOk; + } + initted = TRUE; + printDlg.lStructSize = sizeof printDlg; + printDlg.hwndOwner = NULL; + printDlg.Flags = PD_RETURNDC|PD_RETURNDEFAULT; + if (PrintDlg(&printDlg) != 0 && printDlg.hDC) { + getPageDim( printDlg.hDC ); + DeleteDC( printDlg.hDC ); + } +#ifdef LATER + DEVMODE * printMode; + HDC hDc; + char ptrInfo[80]; + char ptrDrvrDvr[80]; + char *temp; + char *ptrDevice; + char *ptrDrvr; + char *ptrPort; + int size; + int rc; + FARPROC extDeviceMode; + FARPROC deviceMode; + HINSTANCE hDriver; + + GetProfileString("windows", "device", "", ptrInfo, sizeof ptrInfo ); + if (ptrInfo[0] == 0) { + mswFail( "No Printers are defined" ); + return FALSE; + } + temp = ptrDevice = ptrInfo; + ptrDrvr = ptrPort = NULL; + while (*temp) { + if (*temp == ',') { + *temp++ = 0; + while( *temp == ' ' ) + temp++; + if (!ptrDrvr) + ptrDrvr = temp; + else { + ptrPort = temp; + break; + } + } + else + temp = AnsiNext(temp); + } + strcpy( ptrDrvrDvr, ptrDrvr ); + strcat( ptrDrvrDvr, ".drv" ); + if ((long)(hDriver = LoadLibrary( ptrDrvrDvr )) <= 32) { + mswFail( "printInit: LoadLibrary" ); + return FALSE; + } + if (( extDeviceMode = GetProcAddress( hDriver, "ExtDeviceMode" )) != NULL) { + size = extDeviceMode( mswHWnd, (HANDLE)hDriver, (LPDEVMODE)NULL, (LPSTR)ptrDevice, (LPSTR)ptrPort, (LPDEVMODE)NULL, (LPSTR)NULL, 0 ); + printMode = (DEVMODE*)malloc( size ); + rc = extDeviceMode( mswHWnd, (HANDLE)hDriver, (LPDEVMODE)printMode, (LPSTR)ptrDevice, (LPSTR)ptrPort, (LPDEVMODE)NULL, (LPSTR)NULL, DM_OUT_BUFFER ); +#ifdef LATER + if (rc != IDOK && rc != IDCANCEL) { + mswFail( "printInit: extDeviceMode" ); + return FALSE; + } +#endif + } else if (( deviceMode = GetProcAddress( hDriver, "DeviceMode" )) != NULL) { + rc = deviceMode( mswHWnd, (HANDLE)hDriver, (LPSTR)ptrDevice, (LPSTR)ptrPort ); +#ifdef LATER + if (rc != IDOK && rc != IDCANCEL) { + mswFail( "printInit: deviceMode" ); + return FALSE; + } +#endif + } + + hDc = CreateDC( (LPSTR)ptrDrvr, (LPSTR)ptrDevice, (LPSTR)ptrPort, NULL ); + if (hDc == NULL) { + mswFail("printInit: createDC" ); + abort(); + } + getPageDim( hDc ); + DeleteDC( hDc ); + + FreeLibrary( hDriver ); +#endif + printerOk = TRUE; + return TRUE; +} + + +wBool_t wPrintInit( void ) +{ + if (!printInit()) { + return FALSE; + } + return TRUE; +} + + +void wPrintSetup( wPrintSetupCallBack_p callback ) +{ + if (!printInit()) { + return; + } + /*memset( &printDlg, 0, sizeof printDlg );*/ + printDlg.lStructSize = sizeof printDlg; + printDlg.hwndOwner = NULL; + printDlg.Flags = PD_RETURNDC|PD_PRINTSETUP; + if (PrintDlg(&printDlg) != 0 && printDlg.hDC) { + getPageDim( printDlg.hDC ); + } + if ( callback ) { + callback( TRUE ); + } +} + + +void wPrintGetPageSize( double *w, double *h ) +{ + printInit(); + *w = pageSizeW; + *h = pageSizeH; +} + + +void wPrintGetPhysSize( double *w, double *h ) +{ + printInit(); + *w = physSizeW; + *h = physSizeH; +} + + +HDC mswGetPrinterDC( void ) +{ + if (!printInit()) { + return (HDC)0; + } + /*memset( &printDlg, 0, sizeof printDlg );*/ + printDlg.lStructSize = sizeof printDlg; + printDlg.hwndOwner = NULL; + printDlg.Flags = PD_RETURNDC|PD_NOPAGENUMS|PD_NOSELECTION; + if (PrintDlg(&printDlg) != 0) + return printDlg.hDC; + else + return (HDC)0; +} + + +static wBool_t printAbort = FALSE; +HWND hAbortDlgWnd; +FARPROC lpAbortDlg, lpAbortProc; +static int pageNumber; + +int FAR PASCAL mswAbortDlg( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + if (msg == WM_COMMAND) { + if (WCMD_PARAM_ID == IDCANCEL) { + printAbort = TRUE; + EndDialog( hWnd, wParam ); + return TRUE; + } + } else if (msg == WM_INITDIALOG) { + SetFocus( GetDlgItem( hWnd, IDCANCEL ) ); + return TRUE; + } + return FALSE; +} + + +int FAR PASCAL _export mswAbortProc( HDC hdcPrinter, int Code ) +{ + MSG msg; + while (PeekMessage((LPMSG)&msg, (HWND)0, 0, 0, PM_REMOVE)) { + if (!IsDialogMessage(hAbortDlgWnd, (LPMSG)&msg) ) { + TranslateMessage( (LPMSG)&msg ); + DispatchMessage( (LPMSG)&msg ); + } + } + return !printAbort; +} + + +wBool_t wPrintDocStart( const char * title, int fpageCount, int * copiesP ) +{ + printStatus = FALSE; + pageCount = fpageCount; + pageNumber = 0; + print_d.hDc = mswGetPrinterDC(); + if (print_d.hDc == (HDC)0) { + return FALSE; + } + printStatus = TRUE; + docInfo.cbSize = sizeof docInfo; + docInfo.lpszDocName = title; + docInfo.lpszOutput = NULL; + lpAbortDlg = MakeProcInstance( (FARPROC)mswAbortDlg, mswHInst ); + lpAbortProc = MakeProcInstance( (FARPROC)mswAbortProc, mswHInst ); + SetAbortProc( print_d.hDc, (ABORTPROC)lpAbortProc ); + if (StartDoc( print_d.hDc, &docInfo ) < 0) { + MessageBox( mswHWnd, "Unable to start print job", + NULL, MB_OK|MB_ICONHAND ); + FreeProcInstance( lpAbortDlg ); + FreeProcInstance( lpAbortProc ); + DeleteDC( print_d.hDc ); + return FALSE; + } + printAbort = FALSE; + hAbortDlgWnd = CreateDialog( mswHInst, "MswAbortDlg", mswHWnd, + (DLGPROC)lpAbortDlg ); + /*SetDlgItemText( hAbortDlgWnd, IDM_PRINTAPP, title );*/ + SetWindowText( hAbortDlgWnd, title ); + ShowWindow( hAbortDlgWnd, SW_NORMAL ); + UpdateWindow( hAbortDlgWnd ); + EnableWindow( mswHWnd, FALSE ); + if (copiesP) + *copiesP = printDlg.nCopies; + if (printDlg.nCopies>1) + pageCount *= printDlg.nCopies; + if ( (GetDeviceCaps( printDlg.hDC, RASTERCAPS ) & RC_PALETTE) ) { + newPrintPalette = mswCreatePalette(); + oldPrintPalette = SelectPalette( printDlg.hDC, newPrintPalette, 0 ); + RealizePalette( printDlg.hDC ); + } + return TRUE; +} + +wDraw_p wPrintPageStart( void ) +{ + char pageL[80]; + if (!printStatus) + return NULL; + pageNumber++; + if (pageCount > 0) + wsprintf( pageL, "Page %d of %d", pageNumber, pageCount ); + else + wsprintf( pageL, "Page %d", pageNumber ); + SetDlgItemText( hAbortDlgWnd, IDM_PRINTPAGE, pageL ); + StartPage( printDlg.hDC ); +#ifdef LATER + if (mswPrintPalette) { + SelectPalette( printDlg.hDC, mswPrintPalette, 0 ); + RealizePalette( printDlg.hDC ); + } +#endif + getPageDim( printDlg.hDC ); + SelectClipRgn( print_d.hDc, NULL ); + return &print_d; +} + +wBool_t wPrintPageEnd( wDraw_p d ) +{ + return EndPage( printDlg.hDC ) >= 0; +} + +wBool_t wPrintQuit( void ) +{ + MSG msg; + while (PeekMessage((LPMSG)&msg, (HWND)0, 0, 0, PM_REMOVE)) { + if (!IsDialogMessage(hAbortDlgWnd, (LPMSG)&msg) ) { + TranslateMessage( (LPMSG)&msg ); + DispatchMessage( (LPMSG)&msg ); + } + } + return printAbort; +} + +void wPrintDocEnd( void ) +{ + if (!printStatus) + return; + EndDoc( printDlg.hDC ); + if ( newPrintPalette ) { + SelectPalette( printDlg.hDC, oldPrintPalette, 0 ); + DeleteObject( newPrintPalette ); + newPrintPalette = (HPALETTE)0; + } + + EnableWindow( mswHWnd, TRUE ); + DestroyWindow( hAbortDlgWnd ); + FreeProcInstance( lpAbortDlg ); + FreeProcInstance( lpAbortProc ); + DeleteDC( printDlg.hDC ); + printStatus = FALSE; +} + +wBool_t wPrintFontAlias( const char * font, const char * alias ) +{ + return TRUE; +} + +wBool_t wPrintNewPrinter( const char * printer ) +{ + return TRUE; +} + +wBool_t wPrintNewMargin( const char * name, double t, double b, double l, double r ) +{ + 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 new file mode 100644 index 0000000..bddd081 --- /dev/null +++ b/app/wlib/mswlib/mswsplash.c @@ -0,0 +1,266 @@ +/** + * Splash window for Windows + * $header$ + */ + + /* XTrkCad - Model Railroad CAD + * Copyright (C) 2007 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 <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <ctype.h> +#include <assert.h> +#include "mswint.h" + +extern HINSTANCE mswHInst; +extern HWND mswHWnd; + +static HWND hSplash; + +#define IDAPPNAME 150 +#define IDMESSAGE 200 +#define IDBITMAP 250 + +static LPWORD lpwAlign( LPWORD lpIn ) +{ + ULONG ul; + + ul = (ULONG) lpIn; + ul +=3; + ul >>=2; + ul <<=2; + return (LPWORD) ul; +} + +/** + * Draw the logo bitmap. Thanks to Charles Petzold. + */ + +BOOL +PaintBitmap( HWND hWnd, HBITMAP hBmp ) +{ + HDC hdc, hdcMem; + RECT rect; + + UpdateWindow( hWnd ); + + /* get device context for destination window ( the dialog control ) */ + hdc = GetDC( hWnd ); + GetClientRect( hWnd, &rect ); + + /* create a memory dc holding the bitmap */ + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdcMem, hBmp ); + + /* + show it in the uppler left corner + the window is created with the size of the bitmap, so there is no need + for any special transformation + */ + + BitBlt( hdc, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, + hdcMem, 0, 0, SRCCOPY ); + + /* release the DCs that are not needed any more */ + DeleteDC( hdcMem ); + ReleaseDC( hWnd, hdc ); + + return( 0 ); +} + +/** + * This is the dialog procedure for the splash window. Main activity is to + * catch the WM_PAINT message and draw the logo bitmap into that area. + */ + +BOOL CALLBACK +SplashDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static HWND hWndBmp; + static HBITMAP hBmp; + + switch( msg ) { + case WM_INITDIALOG: + /* bitmap handle is passed at dialog creation */ + hBmp = (HBITMAP)lParam; + + hWndBmp = GetDlgItem( hDlg, IDBITMAP ); + return TRUE; + case WM_PAINT: + /* paint the logo bitmap */ + PaintBitmap( hWndBmp, hBmp ); + break; + case WM_DESTROY: + /* destroy the bitmap */ + DeleteObject( hBmp ); + break; + } + return FALSE; +} + +/** + * Show the splash screen. For display of the splash screen, a dialog template is + * created in memory. This template has three static elements: + * - the logo + * - the application name + * - the progress message + * + * return TRUE if successful, FALSE otherwise. + * + */ + +int +wCreateSplash( char *appname, char *appver ) +{ + HGLOBAL hgbl; + LPDLGTEMPLATE lpdt; + LPWORD lpw; + LPDLGITEMTEMPLATE lpdit; + int cxDlgUnit, cyDlgUnit; + int cx, cy; + char *pszBuf; + HBITMAP hBmp; + BITMAP bmp; + char logoPath[MAX_PATH]; + + /* find the size of a dialog unit */ + cxDlgUnit = LOWORD(GetDialogBaseUnits()); + cyDlgUnit = HIWORD(GetDialogBaseUnits()); + + /* load the logo bitmap */ + sprintf( logoPath, "%s\\logo.bmp", wGetAppLibDir()); + hBmp = LoadImage( mswHInst, logoPath, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_LOADFROMFILE ); + if( !hBmp ) + return( 0 ); + + /* get info about the loaded logo file */ + GetObject( hBmp, sizeof(BITMAP), (LPVOID)&bmp ); + + /* calculate the size of dialog box */ + cx = (bmp.bmWidth * 4) / cxDlgUnit; /* start with the size of the bitmap */ + cy = (bmp.bmHeight * 8) / cyDlgUnit + 20; /* 20 is enough for two lines of text and some room */ + + /* allocate memory block for dialog template */ + hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024); + if (!hgbl) + return -1; + lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl); + + /* Define a dialog box. */ + lpdt->style = WS_POPUP | WS_BORDER | WS_VISIBLE | DS_MODALFRAME | DS_CENTER; + lpdt->cdit = 3; // number of controls + lpdt->x = 0; lpdt->y = 0; + lpdt->cx = cx; lpdt->cy = cy; + + lpw = (LPWORD) (lpdt + 1); + *lpw++ = 0; /* no menu */ + *lpw++ = 0; /* predefined dialog box class (by default) */ + *lpw++ = 0; + + /* add the static control for the logo bitmap */ + lpdit = (LPDLGITEMTEMPLATE)lpwAlign(lpw); + lpdit->x = 0; lpdit->y = 0; + lpdit->cx = (SHORT)((bmp.bmWidth * 4) / cxDlgUnit); + lpdit->cy = (SHORT)((bmp.bmHeight * 8) / cyDlgUnit); + + lpdit->id = IDBITMAP; + lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT; + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; /* static class */ + + lpw += 1+MultiByteToWideChar (CP_ACP, 0, "Logo should be here...", -1, (LPWSTR)lpw, 50); + + /* add the static control for the program title */ + lpdit = (LPDLGITEMTEMPLATE)lpwAlign(lpw); + + lpdit->x = 2; lpdit->y = (short)( 1 + (bmp.bmHeight * 8) / cyDlgUnit ); + lpdit->cx = cx - 2; lpdit->cy = cyDlgUnit; + lpdit->id = IDAPPNAME; + lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER; + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; /* static class */ + + /* create the title string */ + pszBuf = malloc( strlen( appname ) + strlen( appver ) + 2 ); + if( !pszBuf ) + return( 0 ); + sprintf( pszBuf, "%s %s", appname, appver ); + + lpw += 1+MultiByteToWideChar (CP_ACP, 0, pszBuf, -1, (LPWSTR)lpw, 50); + + /* add the static control for the loading message */ + lpdit = (LPDLGITEMTEMPLATE)lpwAlign(lpw); + lpdit->x = 2; lpdit->y = (short)(bmp.bmHeight * 8) / cyDlgUnit + 10; + lpdit->cx = cx - 2; lpdit->cy = cyDlgUnit; + lpdit->id = IDMESSAGE; + lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT; + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; /* static class */ + + lpw += 1+MultiByteToWideChar (CP_ACP, 0, "Starting Application...", -1, (LPWSTR)lpw, 50); + + /* create the dialog */ + GlobalUnlock(hgbl); + hSplash = CreateDialogIndirectParam( mswHInst, (LPDLGTEMPLATE) hgbl, + mswHWnd, (DLGPROC)SplashDlgProc, (LPARAM)hBmp ); + GetLastError(); + + /* free allocated memory */ + GlobalFree(hgbl); + free( pszBuf ); + + /* that's it */ + return 1; +} + + +/** + * Update the progress message inside the splash window + * msg text message to display + * return nonzero if ok + */ + +int +wSetSplashInfo( char *msg ) +{ + if( msg ) { + SetWindowText( GetDlgItem( hSplash, IDMESSAGE ), msg ); + wFlush(); + return TRUE; + } + wFlush(); + return FALSE; +} + +/** + * Remove the splash window from the screen. + */ + +void +wDestroySplash(void) +{ + DestroyWindow( hSplash ); + return; +}
\ No newline at end of file diff --git a/app/wlib/mswlib/mswtext.c b/app/wlib/mswlib/mswtext.c new file mode 100644 index 0000000..95f6268 --- /dev/null +++ b/app/wlib/mswlib/mswtext.c @@ -0,0 +1,383 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <stdio.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Multi-line Text Boxes + * + ***************************************************************************** + */ + +static LOGFONT fixedFont = { + /* Initial default values */ + -18, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + FIXED_PITCH|FF_MODERN, /* P&F */ + "Courier" }; +static HFONT fixedTextFont, prevTextFont; + +struct wText_t { + WOBJ_COMMON + HANDLE hText; + }; + +BOOL_T textPrintAbort = FALSE; + + +void wTextClear( + wText_p b ) +{ + long rc; + rc = SendMessage( b->hWnd, EM_SETREADONLY, 0, 0L ); +#ifdef WIN32 + rc = SendMessage( b->hWnd, EM_SETSEL, 0, -1 ); +#else + rc = SendMessage( b->hWnd, EM_SETSEL, 1, MAKELONG( 0, -1 ) ); +#endif + rc = SendMessage( b->hWnd, WM_CLEAR, 0, 0L ); + if ( b->option&BO_READONLY ) + rc = SendMessage( b->hWnd, EM_SETREADONLY, 1, 0L ); +} + + +void wTextAppend( + wText_p b, + const char * text ) +{ + HANDLE hMem; + char * pMem, *cp; + int len, textSize; + long rc; + long lc; + len = strlen(text); + if (len <= 0) + return; + for (cp= CAST_AWAY_CONST text; *cp; cp++) { + if ( *cp == '\n' ) + len++; + } + hMem = GlobalAlloc( GHND, (DWORD)len+10+1 ); + pMem = (char*)GlobalLock( hMem ); + for (cp=pMem; *text; cp++,text++) { + if (*text == '\n') { + *cp++ = '\r'; + *cp = '\n'; + } else + *cp = *text; + } + textSize = LocalSize( b->hText ); + if ((long)textSize+(long)len > 10000L) { + if (len < 1024) + len = 1024; +#ifdef WIN32 + rc = SendMessage( b->hWnd, EM_SETSEL, 0, len ); +#else + rc = SendMessage( b->hWnd, EM_SETSEL, 0, MAKELONG( 0, len ) ); +#endif + rc = SendMessage( b->hWnd, WM_CLEAR, 0, 0L ); +#ifdef WIN32 + rc = SendMessage( b->hWnd, EM_SCROLLCARET, 0, 0 ); +#else + rc = SendMessage( b->hWnd, EM_SETSEL, 0, MAKELONG( 32767, 32767 ) ); +#endif + } + lc = SendMessage( b->hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L ); + if ( lc < 0 ) + lc = 0; + GlobalUnlock( hMem ); + rc = OpenClipboard( b->hWnd ); + rc = EmptyClipboard(); + rc = (long)SetClipboardData( CF_TEXT, hMem ); + rc = CloseClipboard(); + rc = SendMessage( b->hWnd, EM_SETREADONLY, 0, 0L ); + rc = SendMessage( b->hWnd, WM_PASTE, 0, 0L ); + lc -= SendMessage( b->hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L ); +#ifdef LATER + if ( lc < 0 ) + SendMessage( b->hWnd, EM_LINESCROLL, 0, MAKELPARAM((WPARAM)lc,0) ); +#endif + lc = GetWindowTextLength( b->hWnd ); + if ( b->option&BO_READONLY ) + rc = SendMessage( b->hWnd, EM_SETREADONLY, 1, 0L ); +} + + +BOOL_T wTextSave( + wText_p b, + const char * fileName ) +{ + FILE * f; + int lc, l, len; + char line[255]; + + f = wFileOpen( fileName, "w" ); + if (f == NULL) { + MessageBox( ((wControl_p)(b->parent))->hWnd, "TextSave", "", MB_OK|MB_ICONHAND ); + return FALSE; + } + + lc = (int)SendMessage( b->hWnd, EM_GETLINECOUNT, 0, 0L ); + + for ( l=0; l<lc; l++ ) { + *(WORD*)line = sizeof(line)-1; + len = (int)SendMessage( b->hWnd, EM_GETLINE, l, (DWORD)(LPSTR)line ); + line[len] = '\0'; + fprintf( f, "%s\n", line ); + } + fclose( f ); + return TRUE; +} + + +BOOL_T wTextPrint( + wText_p b ) +{ + int lc, l, len; + char line[255]; + HDC hDc; + int lineSpace; + int linesPerPage; + int currentLine; + int IOStatus; + TEXTMETRIC textMetric; + DOCINFO docInfo; + + hDc = mswGetPrinterDC(); + if (hDc == (HDC)0) { + MessageBox( ((wControl_p)(b->parent))->hWnd, "Print", "Cannot print", MB_OK|MB_ICONHAND ); + return FALSE; + } + docInfo.cbSize = sizeof(DOCINFO); + docInfo.lpszDocName = "XTrkcad Log"; + docInfo.lpszOutput = (LPSTR)NULL; + if (StartDoc(hDc, &docInfo) < 0) { + MessageBox( ((wControl_p)(b->parent))->hWnd, "Unable to start print job", NULL, MB_OK|MB_ICONHAND ); + DeleteDC( hDc ); + return FALSE; + } + StartPage( hDc ); + GetTextMetrics( hDc, &textMetric ); + lineSpace = textMetric.tmHeight + textMetric.tmExternalLeading; + linesPerPage = GetDeviceCaps( hDc, VERTRES ) / lineSpace; + currentLine = 1; + + lc = (int)SendMessage( b->hWnd, EM_GETLINECOUNT, 0, 0L ); + + IOStatus = 0; + for ( l=0; l<lc; l++ ) { + *(WORD*)line = sizeof(line)-1; + len = (int)SendMessage( b->hWnd, EM_GETLINE, l, (DWORD)(LPSTR)line ); + TextOut( hDc, 0, currentLine*lineSpace, line, len ); + if (++currentLine > linesPerPage) { + EndPage( hDc ); + currentLine = 1; + IOStatus = EndPage(hDc); + if (IOStatus < 0 || textPrintAbort ) + break; + StartPage( hDc ); + } + } + if (IOStatus >= 0 && !textPrintAbort ) { + EndPage( hDc ); + EndDoc( hDc ); + } + DeleteDC( hDc ); + return TRUE; +} + + +wBool_t wTextGetModified( + wText_p b ) +{ + int rc; + rc = (int)SendMessage( b->hWnd, EM_GETMODIFY, 0, 0L ); + return (wBool_t)rc; +} + +int wTextGetSize( + wText_p b ) +{ + int lc, l, li, len=0; + lc = (int)SendMessage( b->hWnd, EM_GETLINECOUNT, 0, 0L ); + for ( l=0; l<lc ; l++ ) { + li = (int)SendMessage( b->hWnd, EM_LINEINDEX, l, 0L ); + len += (int)SendMessage( b->hWnd, EM_LINELENGTH, l, 0L ) + 1; + } + if ( len == 1 ) + len = 0; + return len; +} + +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, (DWORD)(LPSTR)t ); + t += len; + *t++ = '\n'; + s -= len+1; + } + *t++ = '\0'; +} + + +void wTextSetReadonly( + wText_p b, + wBool_t ro ) +{ + if (ro) + b->option |= BO_READONLY; + else + b->option &= ~BO_READONLY; + SendMessage( b->hWnd, EM_SETREADONLY, ro, 0L ); +} + + +void wTextSetSize( + wText_p bt, + wPos_t width, + wPos_t height ) +{ + bt->w = width; + bt->h = height; + if (!SetWindowPos( bt->hWnd, HWND_TOP, 0, 0, + bt->w, bt->h, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("wTextSetSize: SetWindowPos"); + } +} + + +void wTextComputeSize( + wText_p bt, + int rows, + int lines, + wPos_t * w, + wPos_t * h ) +{ + static wPos_t scrollV_w = -1; + static wPos_t scrollH_h = -1; + HDC hDc; + TEXTMETRIC metrics; + + if (scrollV_w < 0) + scrollV_w = GetSystemMetrics( SM_CXVSCROLL ); + if (scrollH_h < 0) + scrollH_h = GetSystemMetrics( SM_CYHSCROLL ); + hDc = GetDC( bt->hWnd ); + GetTextMetrics( hDc, &metrics ); + *w = rows * metrics.tmAveCharWidth + scrollV_w; + *h = lines * (metrics.tmHeight + metrics.tmExternalLeading); + ReleaseDC( bt->hWnd, hDc ); + if (bt->option&BT_HSCROLL) + *h += scrollH_h; +} + + +void wTextSetPosition( + wText_p bt, + int pos ) +{ + long rc; + rc = SendMessage( bt->hWnd, EM_LINESCROLL, 0, MAKELONG( -65535, 0 ) ); +} + +static void textDoneProc( wControl_p b ) +{ + wText_p t = (wText_p)b; + HDC hDc; + hDc = GetDC( t->hWnd ); + SelectObject( hDc, mswOldTextFont ); + ReleaseDC( t->hWnd, hDc ); +} + +static callBacks_t textCallBacks = { + mswRepaintLabel, + textDoneProc, + NULL }; + +wText_p wTextCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + POS_T height ) +{ + wText_p b; + DWORD style; + RECT rect; + int index; + + b = mswAlloc( parent, B_TEXT, labelStr, sizeof *b, NULL, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + style = ES_MULTILINE | ES_LEFT | ES_AUTOVSCROLL | ES_WANTRETURN | + WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL; +#ifdef BT_HSCROLL + if (option & BT_HSCROLL) + style |= WS_HSCROLL | ES_AUTOHSCROLL; +#endif +/* if (option & BO_READONLY) + style |= ES_READONLY;*/ + + b->hWnd = CreateWindow( "EDIT", NULL, + style, b->x, b->y, + width, height, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(TEXT)"); + return b; + } +#ifdef CONTROL3D + Ctl3dSubclassCtl( b->hWnd ); +#endif + + if (option & BT_FIXEDFONT) { + if (fixedTextFont == (HFONT)0) + fixedTextFont = CreateFontIndirect( &fixedFont ); + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)fixedTextFont, (LPARAM)MAKELONG( 1, 0 ) ); + } else if ( !mswThickFont ) { + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + } + + b->hText = (HANDLE)SendMessage( b->hWnd, EM_GETHANDLE, 0, 0L ); + + if (option & BT_CHARUNITS) { + wPos_t w, h; + wTextComputeSize( b, width, height, &w, &h ); + if (!SetWindowPos( b->hWnd, HWND_TOP, 0, 0, + w, h, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("wTextCreate: SetWindowPos"); + } + } + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + + mswAddButton( (wControl_p)b, FALSE, helpStr ); + mswCallBacks[B_TEXT] = &textCallBacks; + return b; +} diff --git a/app/wlib/mswlib/simple-gettext.c b/app/wlib/mswlib/simple-gettext.c new file mode 100644 index 0000000..295d515 --- /dev/null +++ b/app/wlib/mswlib/simple-gettext.c @@ -0,0 +1,522 @@ +/* simple-gettext.c - a simplified version of gettext. + * Copyright (C) 1995, 1996, 1997, 1999, + * 2005 Free Software Foundation, Inc. + * + * This file is part of XTrackCAD. + * + * GnuPG 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. + * + * GnuPG 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 + */ + +/* This is a simplified version of gettext written by Ulrich Drepper. + * It is used for the Win32 version of GnuPG beucase all the overhead + * of gettext is not needed and we have to do some special Win32 stuff. + * I decided that this is far easier than to tweak gettext for the special + * cases (I tried it but it is a lot of code). wk 15.09.99 + */ + +/* + * Based on the simple-gettext from GnuPG a version appropriate for the + * needs of XTrackCAD was derived. This is a workaround for any compiler + * specifics or runtime library dependencies. mf 26.07.09 + */ + +#ifdef USE_SIMPLE_GETTEXT +#if !defined (_WIN32) && !defined (__CYGWIN32__) +#error This file can only be used under Windows or Cygwin32 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <windows.h> + +#include "mswint.h" + +#if _MSC_VER > 1300 + #define stricmp _stricmp + #define strnicmp _strnicmp + #define strdup _strdup + #define fileno _fileno +#endif + +typedef unsigned long u32; + +/* The magic number of the GNU message catalog format. */ +#define MAGIC 0x950412de +#define MAGIC_SWAPPED 0xde120495 + +/* Revision number of the currently used .mo (binary) file format. */ +#define MO_REVISION_NUMBER 0 + + +/* Header for binary .mo file format. */ +struct mo_file_header +{ + /* The magic number. */ + u32 magic; + /* The revision number of the file format. */ + u32 revision; + /* The number of strings pairs. */ + u32 nstrings; + /* Offset of table with start offsets of original strings. */ + u32 orig_tab_offset; + /* Offset of table with start offsets of translation strings. */ + u32 trans_tab_offset; + /* Size of hashing table. */ + u32 hash_tab_size; + /* Offset of first hashing entry. */ + u32 hash_tab_offset; +}; + +struct string_desc +{ + /* Length of addressed string. */ + u32 length; + /* Offset of string in file. */ + u32 offset; +}; + + +struct overflow_space_s +{ + struct overflow_space_s *next; + u32 idx; + char d[1]; +}; + +struct loaded_domain +{ + char *data; + int must_swap; + u32 nstrings; + char *mapped; /* 0 = not yet mapped, 1 = mapped, + 2 = mapped to + overflow space */ + struct overflow_space_s *overflow_space; + struct string_desc *orig_tab; + struct string_desc *trans_tab; + u32 hash_size; + u32 *hash_tab; +}; + +static struct loaded_domain *the_domain; + +/** + * Translate the input string from UTF8 to Windows codepage. + * + * \param str IN string in UTF-8 format to translate. + * \param len IN number of chars to translate + * \param dummy IN ? + * \return pointer to translated string. Free after usage + */ +char * +utf8_to_native( char *str, unsigned int len, int dummy ) +{ + /* maximum output length is size of string * 2 */ + int buflen = (len + 1) * 2; + char *buf = malloc( buflen ); + int wcharLen; + /* maximum result size is size of UTF-8 string */ + char *resBuffer = malloc( len + 1 ); + + if( !resBuffer ) { + resBuffer = "ERROR in UTF-8 MALLOC"; + } else { + /* as Windows has no way fo a direct translation fom UTF-8 to */ + /* the system codepage, we need to take two steps */ + + /* 1. convert from UTF-8 to UTF-16 */ + wcharLen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)str, -1, (LPWSTR)buf, buflen / 2 ); + + /* 2. convert from UTF-8 to system codepage */ + WideCharToMultiByte(CP_ACP, 0, (LPWSTR)buf, wcharLen, resBuffer, len + 1, NULL, NULL ); + + free( buf ); + } + return( resBuffer ); +} + + +static u32 +do_swap_u32( u32 i ) +{ + return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); +} + +#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) ) + + +/* We assume to have `unsigned long int' value with at least 32 bits. */ +#define HASHWORDBITS 32 + +/* The so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ + +static unsigned long +hash_string( const char *str_param ) +{ + unsigned long int hval, g; + const char *str = str_param; + + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (unsigned long int) *str++; + g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + + +static struct loaded_domain * +load_domain( const char *filename ) +{ + FILE *fp; + size_t size; + struct stat st; + struct mo_file_header *data = NULL; + struct loaded_domain *domain = NULL; + size_t to_read; + char *read_ptr; + + fp = fopen( filename, "rb" ); + if( !fp ) + return NULL; /* can't open the file */ + /* we must know about the size of the file */ + if( fstat( fileno(fp ), &st ) + || (size = (size_t)st.st_size) != st.st_size + || size < sizeof (struct mo_file_header) ) { + fclose( fp ); + return NULL; + } + + data = malloc( size ); + if( !data ) { + fclose( fp ); + return NULL; /* out of memory */ + } + + to_read = size; + read_ptr = (char *) data; + do { + unsigned long int nb = fread( read_ptr, 1, to_read, fp ); + if( nb < to_read ) { + fclose (fp); + free(data); + return NULL; /* read error */ + } + read_ptr += nb; + to_read -= nb; + } while( to_read > 0 ); + fclose (fp); + + /* Using the magic number we can test whether it really is a message + * catalog file. */ + if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) { + /* The magic number is wrong: not a message catalog file. */ + free( data ); + return NULL; + } + + domain = calloc( 1, sizeof *domain ); + if( !domain ) { + free( data ); + return NULL; + } + domain->data = (char *) data; + domain->must_swap = data->magic != MAGIC; + + /* Fill in the information about the available tables. */ + switch( SWAPIT(domain->must_swap, data->revision) ) { + case 0: + domain->nstrings = SWAPIT(domain->must_swap, data->nstrings); + domain->orig_tab = (struct string_desc *) + ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset)); + domain->trans_tab = (struct string_desc *) + ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); + domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); + domain->hash_tab = (u32 *) + ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); + break; + + default: /* This is an invalid revision. */ + free( data ); + free( domain ); + return NULL; + } + + /* Allocate an array to keep track of code page mappings. */ + domain->mapped = calloc( 1, domain->nstrings ); + if( !domain->mapped ) { + free( data ); + free( domain ); + return NULL; + } + + return domain; +} + + +/** + * Set the file used for translations. Pass a NULL to disable + * translation. A new filename may be set at anytime. WARNING: + * After changing the filename you should not access any data + * retrieved by gettext(). + */ +int +set_gettext_file ( const char *filename, const char *regkey ) +{ + struct loaded_domain *domain = NULL; + + if( filename && *filename ) { + if( filename[0] == '/' + || ( isalpha(filename[0]) + && filename[1] == ':' + && (filename[2] == '/' || filename[2] == '\\') ) + ) { + /* absolute path - use it as is */ + domain = load_domain( filename ); + } + if (!domain) + return -1; + } + + if( the_domain ) { + struct overflow_space_s *os, *os2; + free( the_domain->data ); + free( the_domain->mapped ); + for (os=the_domain->overflow_space; os; os = os2) { + os2 = os->next; + free (os); + } + free( the_domain ); + the_domain = NULL; + } + the_domain = domain; + return 0; +} + +/** + * Return the required string from the message table. Before returning the result, + * codepage translation from UTF8 to current codepage is performed. + */ + +static const char* +get_string( struct loaded_domain *domain, u32 idx ) +{ + struct overflow_space_s *os; + char *p; + + p = domain->data + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset); + if (!domain->mapped[idx]) + { + size_t plen, buflen; + char *buf; + + domain->mapped[idx] = 1; + + plen = strlen (p); + buf = utf8_to_native (p, plen, -1); + buflen = strlen (buf); + if (buflen <= plen){ + strcpy (p, buf); + free( buf ); + } else { + /* There is not enough space for the translation - store it + in the overflow_space else and mark that in the mapped + array. Because we expect that this won't happen too + often, we use a simple linked list. */ + os = malloc (sizeof *os + buflen); + if (os) + { + os->idx = idx; + strcpy (os->d, buf); + os->next = domain->overflow_space; + domain->overflow_space = os; + p = os->d; + } + else + p = "ERROR in GETTEXT MALLOC"; + free (buf); + } + } + else if (domain->mapped[idx] == 2) + { /* We need to get the string from the overflow_space. */ + for (os=domain->overflow_space; os; os = os->next) + if (os->idx == idx) + return (const char*)os->d; + p = "ERROR in GETTEXT\n"; + } + return (const char*)p; +} + +/** + * This is the translation function itself. + */ + +char * +gettext( char *msgid ) +{ + struct loaded_domain *domain; + size_t act = 0; + size_t top, bottom; + + if( !(domain = the_domain) ) + goto not_found; + + /* Locate the MSGID and its translation. */ + if( domain->hash_size > 2 && domain->hash_tab ) { + /* Use the hashing table. */ + u32 len = strlen (msgid); + u32 hash_val = hash_string (msgid); + u32 idx = hash_val % domain->hash_size; + u32 incr = 1 + (hash_val % (domain->hash_size - 2)); + u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); + + if ( !nstr ) /* Hash table entry is empty. */ + goto not_found; + + if( SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].length) == len + && !strcmp( msgid, + domain->data + SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].offset)) ) + return (char *)get_string( domain, nstr - 1 ); + + for(;;) { + if (idx >= domain->hash_size - incr) + idx -= domain->hash_size - incr; + else + idx += incr; + + nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]); + if( !nstr ) + goto not_found; /* Hash table entry is empty. */ + + if ( SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].length) == len + && !strcmp (msgid, + domain->data + SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].offset))) + return (char *)get_string( domain, nstr-1 ); + } + /* NOTREACHED */ + } + + /* Now we try the default method: binary search in the sorted + array of messages. */ + bottom = 0; + top = domain->nstrings; + while( bottom < top ) { + int cmp_val; + + act = (bottom + top) / 2; + cmp_val = strcmp(msgid, domain->data + + SWAPIT(domain->must_swap, + domain->orig_tab[act].offset)); + if (cmp_val < 0) + top = act; + else if (cmp_val > 0) + bottom = act + 1; + else + return (char *)get_string( domain, act ); + } + + not_found: + return msgid; +} + +/** + * This is the main initialization function for simple gettext. The message file is + * opened and read into memory. The function must be called once before translating + * a string. + * + * The message files are expected to be in a directory named in the UNIXish form en_US + * in the path passed to this function. The filename is expected to be domainname.mo + * + * \param domainname IN domain + * \param dirname IN directory for the message files + * \return always NULL + */ + +char * +bindtextdomain( char *domainname, char *dirname ) +{ + char *loc; + char *dir; + + /* get thread's locale in UNIXish style eg. en_US */ + loc = g_win32_getlocale(); + + /* make sure that path does not end with trailing slash */ + if( dirname[ strlen(dirname) ] == '/' ) + dirname[ strlen(dirname) ] = '\0'; + + /* allocate buffer for filename, 20 bytes should be enough for extension etc. */ + dir = malloc( strlen( domainname ) + strlen( dirname ) + strlen( loc ) + 20 ); + + if( dir ) { + /* create the full filename */ + sprintf( dir, "%s/%s/LC_MESSAGES/%s.mo", dirname, loc, domainname ); + /* load the file */ + set_gettext_file( dir, NULL ); + free( dir ); + } + + free( loc ); + return( NULL ); +} + +/** + * This is a dummy function to maintain source code compatibility + * with other implementations of gettext. + * For this implementation, UTF-8 input encoding is assumed + * + * \param domainname IN domain + * \param codeset In codeset + * \return always NULL + */ + +char * +bind_textdomain_codeset(char *domainname, char *codeset ) +{ + return( NULL ); +} + +/** + * This is a dummy function to maintain source code compatibility + * with other implementations of gettext. + * + * \param domainname IN domain + * \return always NULL + */ + +char * +textdomain( char *domainname ) +{ + return( NULL ); +} +#endif /* USE_SIMPLE_GETTEXT */ diff --git a/app/wlib/mswlib/square10.bmp b/app/wlib/mswlib/square10.bmp new file mode 100644 index 0000000..c45fb75 --- /dev/null +++ b/app/wlib/mswlib/square10.bmp @@ -0,0 +1,6 @@ +#define square10_width 14 +#define square10_height 14 +static unsigned char square10_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff}; |