summaryrefslogtreecommitdiff
path: root/app/wlib
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2016-12-28 16:52:56 +0100
committerJörg Frings-Fürst <debian@jff-webhosting.net>2016-12-28 16:52:56 +0100
commit7b358424ebad9349421acd533c2fa1cbf6cf3e3e (patch)
tree686678532eefed525c242fd214d0cfb2914726c5 /app/wlib
Initial import of xtrkcad version 1:4.0.2-2
Diffstat (limited to 'app/wlib')
-rw-r--r--app/wlib/CMakeLists.txt10
-rw-r--r--app/wlib/gtklib/.directory7
-rw-r--r--app/wlib/gtklib/CMakeLists.txt37
-rw-r--r--app/wlib/gtklib/ChangeLog250
-rw-r--r--app/wlib/gtklib/dynarr.h49
-rw-r--r--app/wlib/gtklib/filesel.c174
-rw-r--r--app/wlib/gtklib/gtkbitmap.c85
-rw-r--r--app/wlib/gtklib/gtkbutton.c461
-rw-r--r--app/wlib/gtklib/gtkcolor.c476
-rw-r--r--app/wlib/gtklib/gtkdraw-cairo.c1212
-rw-r--r--app/wlib/gtklib/gtkdraw.c1044
-rw-r--r--app/wlib/gtklib/gtkfont.c320
-rw-r--r--app/wlib/gtklib/gtkhelp.c733
-rw-r--r--app/wlib/gtklib/gtkint.h180
-rw-r--r--app/wlib/gtklib/gtklist.c1109
-rw-r--r--app/wlib/gtklib/gtkmenu.c873
-rw-r--r--app/wlib/gtklib/gtkmisc.c1210
-rw-r--r--app/wlib/gtklib/gtksimple.c366
-rw-r--r--app/wlib/gtklib/gtksingle.c645
-rw-r--r--app/wlib/gtklib/gtksplash.c142
-rw-r--r--app/wlib/gtklib/gtktext.c524
-rw-r--r--app/wlib/gtklib/gtkwindow.c856
-rw-r--r--app/wlib/gtklib/gtkxpm.c177
-rw-r--r--app/wlib/gtklib/psprint.c1599
-rw-r--r--app/wlib/gtklib/square10.bmp8
-rw-r--r--app/wlib/gtklib/uthash.h960
-rw-r--r--app/wlib/gtklib/wpref.c502
-rw-r--r--app/wlib/include/ctl3d.h5
-rw-r--r--app/wlib/include/getopt.h25
-rw-r--r--app/wlib/include/mswlib.h9
-rw-r--r--app/wlib/include/mswlib.rc13
-rw-r--r--app/wlib/include/wcolors.h42
-rw-r--r--app/wlib/include/wlib.h690
-rw-r--r--app/wlib/mswlib/CMakeLists.txt39
-rw-r--r--app/wlib/mswlib/ChangeLog146
-rw-r--r--app/wlib/mswlib/checksum.c42
-rw-r--r--app/wlib/mswlib/dynarr.h40
-rw-r--r--app/wlib/mswlib/getopt.c87
-rw-r--r--app/wlib/mswlib/gwin32.c146
-rw-r--r--app/wlib/mswlib/mswbitmap.c508
-rw-r--r--app/wlib/mswlib/mswbox.c119
-rw-r--r--app/wlib/mswlib/mswbutt.c387
-rw-r--r--app/wlib/mswlib/mswchksm.c125
-rw-r--r--app/wlib/mswlib/mswchoic.c423
-rw-r--r--app/wlib/mswlib/mswcolor.c362
-rw-r--r--app/wlib/mswlib/mswdraw.c1783
-rw-r--r--app/wlib/mswlib/mswedit.c726
-rw-r--r--app/wlib/mswlib/mswint.h193
-rw-r--r--app/wlib/mswlib/mswlines.c98
-rw-r--r--app/wlib/mswlib/mswlist.c1173
-rw-r--r--app/wlib/mswlib/mswmenu.c1062
-rw-r--r--app/wlib/mswlib/mswmisc.c2778
-rw-r--r--app/wlib/mswlib/mswmsg.c212
-rw-r--r--app/wlib/mswlib/mswpref.c274
-rw-r--r--app/wlib/mswlib/mswprint.c387
-rw-r--r--app/wlib/mswlib/mswsplash.c266
-rw-r--r--app/wlib/mswlib/mswtext.c383
-rw-r--r--app/wlib/mswlib/simple-gettext.c522
-rw-r--r--app/wlib/mswlib/square10.bmp6
-rw-r--r--app/wlib/test/alarmtst.c59
-rw-r--r--app/wlib/test/alarmtst.mak2
-rw-r--r--app/wlib/test/bits.bmp6
-rw-r--r--app/wlib/test/boxtest.c31
-rw-r--r--app/wlib/test/boxtest.mak2
-rw-r--r--app/wlib/test/btest.c212
-rw-r--r--app/wlib/test/btest.mak2
-rw-r--r--app/wlib/test/colortst.c87
-rw-r--r--app/wlib/test/colortst.mak2
-rw-r--r--app/wlib/test/draw.c82
-rw-r--r--app/wlib/test/draw.mak2
-rw-r--r--app/wlib/test/dtest.bmp18
-rw-r--r--app/wlib/test/fred.bmp9
-rw-r--r--app/wlib/test/fred.c169
-rw-r--r--app/wlib/test/fred.mak2
-rw-r--r--app/wlib/test/listtest.c96
-rw-r--r--app/wlib/test/listtest.mak2
-rw-r--r--app/wlib/test/splash.rc17
-rw-r--r--app/wlib/test/test.vcproj202
-rw-r--r--app/wlib/test/testapp.c125
-rw-r--r--app/wlib/test/wtest.def9
-rw-r--r--app/wlib/test/wtest.icobin0 -> 1278 bytes
-rw-r--r--app/wlib/test/wtest.mak23
-rw-r--r--app/wlib/test/wtest.rc22
83 files changed, 28261 insertions, 0 deletions
diff --git a/app/wlib/CMakeLists.txt b/app/wlib/CMakeLists.txt
new file mode 100644
index 0000000..4fa7469
--- /dev/null
+++ b/app/wlib/CMakeLists.txt
@@ -0,0 +1,10 @@
+PROJECT(wlib)
+
+INCLUDE_DIRECTORIES("${wlib_SOURCE_DIR}/include")
+
+IF(XTRKCAD_USE_GTK)
+ ADD_SUBDIRECTORY(gtklib)
+ELSE(XTRKCAD_USE_GTK)
+ ADD_SUBDIRECTORY(mswlib)
+ENDIF(XTRKCAD_USE_GTK)
+
diff --git a/app/wlib/gtklib/.directory b/app/wlib/gtklib/.directory
new file mode 100644
index 0000000..2482e35
--- /dev/null
+++ b/app/wlib/gtklib/.directory
@@ -0,0 +1,7 @@
+[Dolphin]
+HeaderColumnWidths=500,64,124
+SortOrder=1
+SortRole=date
+Timestamp=2015,10,6,20,51,0
+Version=3
+ViewMode=1
diff --git a/app/wlib/gtklib/CMakeLists.txt b/app/wlib/gtklib/CMakeLists.txt
new file mode 100644
index 0000000..fabc5d8
--- /dev/null
+++ b/app/wlib/gtklib/CMakeLists.txt
@@ -0,0 +1,37 @@
+FILE(GLOB HEADERS *.h)
+
+SET(SOURCES
+ gtkbitmap.c
+ gtkbutton.c
+ gtkcolor.c
+ filesel.c
+ gtkfont.c
+ gtkhelp.c
+ gtklist.c
+ gtkmenu.c
+ gtkmisc.c
+ gtksimple.c
+ gtksingle.c
+ gtksplash.c
+ gtktext.c
+ gtkwindow.c
+ gtkxpm.c
+ psprint.c
+ wpref.c
+ )
+
+IF(XTRKCAD_USE_GTK_CAIRO)
+ SET(SOURCES ${SOURCES} gtkdraw-cairo.c)
+ELSE(XTRKCAD_USE_GTK_CAIRO)
+ SET(SOURCES ${SOURCES} gtkdraw.c)
+ENDIF(XTRKCAD_USE_GTK_CAIRO)
+
+SET_SOURCE_FILES_PROPERTIES(wpref.c PROPERTIES COMPILE_FLAGS -DEXPORT=)
+
+INCLUDE_DIRECTORIES(${XTrkCAD_BINARY_DIR})
+INCLUDE_DIRECTORIES(${GTK_INCLUDE_DIRS})
+INCLUDE_DIRECTORIES(${GTK_WEBKIT_INCLUDE_DIRS})
+
+ADD_LIBRARY(xtrkcad-wlib ${HEADERS} ${SOURCES})
+TARGET_LINK_LIBRARIES(xtrkcad-wlib ${GTK_LIBRARIES})
+TARGET_LINK_LIBRARIES(xtrkcad-wlib ${GTK_WEBKIT_LIBRARIES})
diff --git a/app/wlib/gtklib/ChangeLog b/app/wlib/gtklib/ChangeLog
new file mode 100644
index 0000000..ef2bd09
--- /dev/null
+++ b/app/wlib/gtklib/ChangeLog
@@ -0,0 +1,250 @@
+Apr 28, 2010
+ FIX: Daniel Spagnol
+ gtkwindow.c, wpref.c: now, wGetAppLibDir can be called before
+ wWinMainCreate is called.
+
+Dec 12, 2009
+ FIX: Martin Fischer
+ gtkint.h, gtkwindow.c: refactoring, remove unused globals and
+ added some comments.
+
+Dec 07, 2010
+ FIX: Martin Fischer / Robert Heller
+ gtkfont.c: use newer Pango functions only after checking for correct
+ version at compile time.
+
+Oct 03, 2009
+ FIX: Daniel Spagnol
+ gtkdraw-cairo.c: linux still crashed due to a cairo context access
+ after its drawable destruction
+
+Oct 03, 2009
+ FIX: Daniel Spagnol
+ gtkbutton.c gtkint.h gtkmenu.c gtkmisc.c: workaround for OSX with
+ GTK-Quartz -> pixmaps are not rendered when using the mask;
+ and replaced gtk_pixmap_new deprecated function with
+ gtk_image_new_from_pixmap
+
+Oct 02, 2009
+ FIX: Daniel Spagnol
+ gtkdraw-cairo.c: linux crashed due to a cairo context access after its
+ drawable destruction
+
+Sep 27, 2009
+ FIX: Daniel Spagnol
+ gtkbitmap.c: image in about dialog box was not being displayed
+
+Sep 26, 2009
+ FIX: Daniel Spagnol
+ gtkfont: deallocate PangoFontDescription using the right function
+
+Sep 25, 2009
+ FIX: Daniel Spagnol
+ gtkbitmap.c: EXC_BAD_ACCESS when displaying about dialog
+
+Sep 25, 2009
+ ENH: Daniel Spagnol
+ gtkdraw-cairo.c gtkdraw.c gtkfont.c gtkint.h gtksimple.c wlib.h:
+ replace the old font select dialog with the GTK standard one, and some
+ code cleanup
+
+Sep 23, 2009
+ FIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkbitmap.c gtkmisc.c: implement wCreateBitmap
+
+Sep 22, 2009
+ FIX: Daniel Spagnol
+ gtkdraw-cairo.c: text in layout and selection were not aligned
+
+Sep 22, 2009
+ FIX: Daniel Spagnol
+ CMakeLists.txt gtkbitmap.c gtkint.h: file created as a workaround to
+ get the source compiled under POSIX and OSX after wCreateBitmap
+ feature
+
+Aug 12, 2009
+ ENH: Matthew Sheets
+ wpref.c: initialize with system default config from /etc
+
+Jul 29, 2009
+ ENH: Martin Fischer <m_fischer@users.sourceforge.net>
+ wpref.c: Create directory .xtrkcad silently
+
+Jun 24, 2009
+ ENH: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkwindow.c gtkmisc.c gtkint.h wpref.c: add option
+ to select configuration file
+
+Version 4.0.3a
+==============
+
+
+Jun 09, 2009
+ FIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkdraw.c: Fix compiler warning
+May 31, 2009
+ FIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtksplash.c: popups during startup are now shown above
+ splash screen
+
+May 31, 2009
+ FIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkmisc.c: fixed problem with some icons
+
+May 30, 2009
+ FIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtklist.c: fixed the 'missing scrollbar' bug - finally!
+
+May 29, 2008
+ FIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkmisc.c: bug fix in wNoticeEx
+
+May 21, 2009
+ ENH: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkhelp.c: better error message
+
+May 15, 2009
+ ENH: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkwindow.c, gtkmisc.c, psprint.c, gtktext.c
+ gtkfilsel.c, gtksingle.c: new message box with icon
+
+Jul 11, 2008
+ ENH: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkwindow.c: closing app can now be canceled by the user
+
+Jul 11, 2008
+ ENH: Steve DeCaux
+ gtdraw-cairo.c: convert strings to UTF8
+
+Jul 01, 2008
+ ENH: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtksplash.c: added #ifdef's for backward compatibility to GTK 2.4
+
+Feb 01. 2008
+ ENH: Martin Fischer <m_fischer@users.sourceforge.net>
+ psprint.c, gtkint.h: added file selector for print to file, made
+ Postscript digit representation independent of current locale
+
+Jan 28, 2008
+ ENH: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtkfilsel.c: Gettext support added.
+
+Jan 28, 2008
+ FIX: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtkwindow.c: Dynamically allocate and form some global translatable
+ strings.
+
+Jan 27, 2008
+ FIX: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtkhelp.c: String XTrkCad changed to XTrackCAD.
+
+Jan, 27, 2008
+ FIX: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtkwindows.c: fixed problem with missing scroll bars
+
+Jan 24,2008
+ IMPROVMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ wpref.c: increase floting point precision when storing floats in rc
+ file
+
+Jan 22, 2008
+ ENH: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtkwindow.c: wExit(): Free user locale before exit.
+
+Jan 21, 2008
+ ENH: Gettext support added. Modified files:
+ gtkbutton.c
+ gtkfont.c
+ gtkhelp.c
+ gtklist.c
+ psprint.c
+ wpref.c
+
+Jan 20, 2008
+ FIX: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtkdraw.c/gtkdraw-cairo.c: wDrawSetSize(): Return immediately,
+ if given width or height is negative. Negative values crashed
+ the program. This can be seen at least in Add Turnout and Add
+ Structure dialogs by resizing the dialog vertically smaller.
+
+Jan 16, 2008
+ FIX: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtkmisc.c: gtkConvertInput(): If the input string is already
+ UTF-8 encoded, then return it untouched.
+
+Jan 15, 2008
+ IMPROVEMENT: Mikko Nissinen <mni77@users.sourceforge.net>
+ Basic gettext support added.
+ CMakeLists.txt
+
+Nov 30, 2007
+ FIX: Timothy M. Shead
+ gtkfont.c: make sure that font initialization is run first
+
+Nov 29, 2007
+ FIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkhelp.c: an existing help window is now brought to the foreground
+ if the user selects Help
+
+Nov 12, 2007
+ FIX: Mikko Nissinen <mni77@users.sourceforge.net>
+ gtksimple.c: wMessageCreateEx -> Reset the pango font size back
+ to normal before returning the function. All dialogs created after
+ the tip of the day dialog had incorrectly positioned labels,
+ because the width of the text was calculated with the large font.
+
+Nov 12, 2007
+ IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkhelp.c: Converted help system to gtkhtml-2. This allows to
+ us standard HTML files to be used for help documentation.
+
+Oct 28, 2007
+ IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkmenu.c: Help drop-down is no longer right aligned.
+
+Sep 28, 2007
+ IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtksimple.c: wMessageCreate has been extended to
+ wMessageCreateEx. New function allows adding flags. Setting
+ a large or a small font are first uses. Added a compatibility
+ macro wMessageCreate for older code.
+
+Sep 15, 2007
+ IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtksplash.c: added splash window for program startup
+
+Jul 24, 2007
+ IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkdraw.c: added support for wheel mouse
+
+Jun 16, 2007
+ IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ wpref.c: added wGetUserHomeDir()
+
+Feb 25, 2007
+ BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ wpref.c: Rephrased error message for lib-directory not found
+
+Feb 23, 2007
+ BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkfont.c: Typo in window title corrected
+
+Version 4.0.1
+=============
+
+Mar, 30th 2006
+ BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkmisc.c: changed wPause to use SYSV signal handling funtions
+
+Mar, 29th 2006
+ BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkmisc.c, gtkbutton.c, gtksimple.c: small changes to help Solaris port
+
+ IMPROVEMENT: Martin Fischer <m_fischer@users.sourceforge.net>
+ wpref.c: Optimized the checking for directories in wGetAppLibDir and
+ rephrased the error message if initialization files cannot be found
+
+ BUGFIX: Martin Fischer <m_fischer@users.sourceforge.net>
+ gtkwindow.c: Fixed resizing problems when enlarging dialog boxes
+
+ BUGFIX:
diff --git a/app/wlib/gtklib/dynarr.h b/app/wlib/gtklib/dynarr.h
new file mode 100644
index 0000000..13c0ede
--- /dev/null
+++ b/app/wlib/gtklib/dynarr.h
@@ -0,0 +1,49 @@
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+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; }
diff --git a/app/wlib/gtklib/filesel.c b/app/wlib/gtklib/filesel.c
new file mode 100644
index 0000000..4c737ae
--- /dev/null
+++ b/app/wlib/gtklib/filesel.c
@@ -0,0 +1,174 @@
+/** \file filesel.c
+ * Create and handle file selectors
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+
+#include "gtkint.h"
+#include "i18n.h"
+
+struct wFilSel_t {
+ GtkWidget * window;
+ wFilSelCallBack_p action;
+ void * data;
+ int pattCount;
+ GtkFileFilter *filter[ 10 ];
+ wFilSelMode_e mode;
+ int opt;
+ const char * title;
+ wWin_p parent;
+ };
+
+
+/**
+ * Create a new file selector. Only the internal data structures are
+ * set up, no dialog is created.
+ *
+ * \param w IN parent window
+ * \param mode IN ?
+ * \param opt IN ?
+ * \param title IN dialog title
+ * \param pattList IN list of selection patterns
+ * \param action IN callback
+ * \param data IN ?
+ * \return the newly created file selector structure
+ */
+
+struct wFilSel_t * wFilSelCreate(
+ wWin_p w,
+ wFilSelMode_e mode,
+ int opt,
+ const char * title,
+ const char * pattList,
+ wFilSelCallBack_p action,
+ void * data )
+{
+ struct wFilSel_t *fs;
+ int count;
+ char * cp;
+ GtkFileFilter *filter;
+
+ fs = (struct wFilSel_t*)malloc(sizeof *fs);
+ if (!fs)
+ return NULL;
+
+ fs->parent = w;
+ fs->window = 0;
+ fs->mode = mode;
+ fs->opt = opt;
+ fs->title = strdup( title );
+ fs->action = action;
+ fs->data = data;
+
+ if (pattList) {
+ //create filters for the passed filter list
+ cp = strdup(pattList);
+ count = 0;
+ // names and patterns are separated by |
+ cp = strtok( cp, "|" );
+ while ( cp && count < 9 ) {
+ fs->filter[ count ] = gtk_file_filter_new ();
+ gtk_file_filter_set_name ( fs->filter[ count ], cp );
+ cp = strtok( NULL, "|" );
+ gtk_file_filter_add_pattern (fs->filter[ count ], cp );
+ cp = strtok( NULL, "|" );
+ count++;
+ }
+ // finally add the all files pattern
+ fs->filter[ count ] = gtk_file_filter_new ();
+ gtk_file_filter_set_name( fs->filter[ count ], _("All files") );
+ gtk_file_filter_add_pattern( fs->filter[ count ], "*" );
+ fs->pattCount = count++;
+ } else {
+ fs->filter[ 0 ] = NULL;
+ fs->pattCount = 0;
+ }
+ return fs;
+}
+
+/**
+ * Show and handle the file selection dialog.
+ *
+ * \param fs IN file selection
+ * \param dirName IN starting directory
+ * \return always TRUE
+ */
+
+int wFilSelect( struct wFilSel_t * fs, const char * dirName )
+{
+ char name[1024];
+ char *fileName;
+ const char *base;
+ int i;
+
+ char * cp;
+ if (fs->window == NULL) {
+ fs->window = gtk_file_chooser_dialog_new( fs->title,
+ GTK_WINDOW( fs->parent->gtkwin ),
+ (fs->mode == FS_LOAD ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE ),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ (fs->mode == FS_LOAD ? GTK_STOCK_OPEN : GTK_STOCK_SAVE ), GTK_RESPONSE_ACCEPT,
+ NULL );
+ if (fs->window==0) abort();
+ // get confirmation before overwritting an existing file
+ gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(fs->window), TRUE );
+
+ // add the file filters to the dialog box
+ if( fs->pattCount ) {
+ for( i = 0; i <= fs->pattCount; i++ ) {
+ gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( fs->window ), fs->filter[ i ] );
+ }
+ }
+ /** \todo for loading a shortcut folder could be added linking to the example directory */
+
+ }
+ strcpy( name, dirName );
+ cp = name+strlen(name);
+ if (cp[-1] != '/') {
+ *cp++ = '/';
+ *cp = 0;
+ }
+ if( fs->mode == FS_SAVE )
+ gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(fs->window), name );
+
+ if( gtk_dialog_run( GTK_DIALOG( fs->window )) == GTK_RESPONSE_ACCEPT ) {
+ fileName = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(fs->window) );
+ if (fs->data)
+ strcpy( fs->data, fileName );
+ if (fs->action) {
+ base = strrchr( fileName, '/' );
+ if (base==0) {
+ fprintf(stderr,"no / in %s\n", fileName );
+ return 1;
+ }
+ fs->action( fileName, base+1, fs->data );
+ }
+ }
+ gtk_widget_hide( GTK_WIDGET( fs->window ));
+
+ return 1;
+}
diff --git a/app/wlib/gtklib/gtkbitmap.c b/app/wlib/gtklib/gtkbitmap.c
new file mode 100644
index 0000000..8f85951
--- /dev/null
+++ b/app/wlib/gtklib/gtkbitmap.c
@@ -0,0 +1,85 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkbitmap.c,v 1.5 2009-09-27 04:28:03 dspagnol Exp $
+ */
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2009 Daniel Spagnol
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "gtkint.h"
+
+
+struct wBitmap_t {
+ WOBJ_COMMON
+};
+
+/**
+ * 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 options, wIcon_p iconP )
+{
+ wBitmap_p bt;
+ GdkPixbuf *pixbuf;
+
+ bt = gtkAlloc( parent, B_BITMAP, x, y, NULL, sizeof *bt, NULL );
+ bt->w = iconP->w;
+ bt->h = iconP->h;
+ bt->option = options;
+
+ /*
+ * Depending on the platform, parent->widget->window might still be null
+ * at this point. The window allocation should be forced before creating
+ * the pixmap.
+ */
+ if ( parent->widget->window == NULL )
+ gtk_widget_realize( parent->widget ); /* force allocation, if pending */
+
+ pixbuf = gdk_pixbuf_new_from_xpm_data( (const char**)iconP->bits );
+ GtkWidget *image = gtk_image_new_from_pixbuf( pixbuf );
+
+ gtk_widget_show( image );
+
+ bt->widget = gtk_fixed_new();
+ gtk_container_add( GTK_CONTAINER(bt->widget), image );
+ gtk_widget_show( bt->widget );
+
+ gtkComputePos( (wControl_p)bt );
+ gtkControlGetSize( (wControl_p)bt );
+ gtk_fixed_put( GTK_FIXED( parent->widget ), bt->widget, bt->realX, bt->realY );
+
+ g_object_unref( pixbuf );
+
+ return( (wControl_p)bt );
+}
+
diff --git a/app/wlib/gtklib/gtkbutton.c b/app/wlib/gtklib/gtkbutton.c
new file mode 100644
index 0000000..7780535
--- /dev/null
+++ b/app/wlib/gtklib/gtkbutton.c
@@ -0,0 +1,461 @@
+/** \file gtkbutton.c
+ * Toolbar button creation and handling
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkbutton.c,v 1.8 2009-10-03 04:49:01 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "gtkint.h"
+#include "i18n.h"
+
+#define MIN_BUTTON_WIDTH (80)
+
+/*
+ *****************************************************************************
+ *
+ * Simple Buttons
+ *
+ *****************************************************************************
+ */
+
+struct wButton_t {
+ WOBJ_COMMON
+ GtkLabel * labelG;
+ GtkWidget * imageG;
+ wButtonCallBack_p action;
+ int busy;
+ int recursion;
+ };
+
+
+void wButtonSetBusy( wButton_p bb, int value ) {
+ bb->recursion++;
+ gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(bb->widget), value );
+ bb->recursion--;
+ bb->busy = value;
+}
+
+
+void gtkSetLabel(
+ GtkWidget *widget,
+ long option,
+ const char * labelStr,
+ GtkLabel * * labelG,
+ GtkWidget * * imageG )
+{
+ wIcon_p bm;
+ GdkPixbuf *pixbuf;
+
+ GdkPixmap * pixmap;
+ GdkBitmap * mask;
+
+ GtkWidget * hbox;
+ if (widget == 0) abort();
+ if (labelStr){
+ if (option&BO_ICON) {
+ bm = (wIcon_p)labelStr;
+
+ // for XPM files use the pixbuf functions
+ if( bm->gtkIconType == gtkIcon_pixmap ) {
+ pixbuf = gdk_pixbuf_new_from_xpm_data( (const char**)bm->bits );
+ if (*imageG==NULL) {
+ *imageG = gtk_image_new_from_pixbuf( pixbuf );
+ gtk_container_add( GTK_CONTAINER( widget ), *imageG );
+ gtk_widget_show( *imageG );
+ } else {
+ gtk_image_set_from_pixbuf( GTK_IMAGE(*imageG), pixbuf );
+ }
+ g_object_unref( pixbuf );
+ } else {
+ // otherwise use the conversion to XPM
+ /** \todo { Should use the way via a pixbuf as well } */
+ pixmap = gtkMakeIcon( widget, bm, &mask );
+ if (*imageG==NULL) {
+ *imageG = gtk_image_new_from_pixmap( pixmap, NULL );
+ gtk_widget_show( *imageG );
+ gtk_container_add( GTK_CONTAINER( widget ), *imageG );
+ } else {
+ gtk_image_set_from_pixmap( GTK_IMAGE(*imageG), pixmap, NULL );
+ }
+ gdk_pixmap_unref( pixmap );
+ gdk_bitmap_unref( mask );
+ }
+ } else {
+ if (*labelG==NULL) {
+ *labelG = (GtkLabel*)gtk_label_new( gtkConvertInput(labelStr) );
+ gtk_container_add( GTK_CONTAINER(widget), (GtkWidget*)*labelG );
+ gtk_widget_show( (GtkWidget*)*labelG );
+ } else {
+ gtk_label_set( *labelG, gtkConvertInput(labelStr) );
+ }
+ }
+ }
+}
+
+void wButtonSetLabel( wButton_p bb, const char * labelStr) {
+ gtkSetLabel( bb->widget, bb->option, labelStr, &bb->labelG, &bb->imageG );
+}
+
+
+
+void gtkButtonDoAction(
+ wButton_p bb )
+{
+ if (bb->action)
+ bb->action( bb->data );
+}
+
+
+static void pushButt(
+ GtkWidget *widget,
+ gpointer value )
+{
+ wButton_p b = (wButton_p)value;
+ if (debugWindow >= 2) printf("%s button pushed\n", b->labelStr?b->labelStr:"No label" );
+ if (b->recursion)
+ return;
+ if (b->action)
+ b->action(b->data);
+ if (!b->busy) {
+ b->recursion++;
+ gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(b->widget), FALSE );
+ b->recursion--;
+ }
+}
+
+wButton_p wButtonCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ long option,
+ wPos_t width,
+ wButtonCallBack_p action,
+ void * data )
+{
+ wButton_p b;
+ b = gtkAlloc( parent, B_BUTTON, x, y, labelStr, sizeof *b, data );
+ b->option = option;
+ b->action = action;
+ gtkComputePos( (wControl_p)b );
+
+ b->widget = gtk_toggle_button_new();
+
+ gtk_signal_connect (GTK_OBJECT(b->widget), "clicked",
+ GTK_SIGNAL_FUNC(pushButt), b );
+ if (width > 0)
+ gtk_widget_set_size_request( b->widget, width, -1 );
+ wButtonSetLabel( b, labelStr );
+
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+ if (option & BB_DEFAULT) {
+ GTK_WIDGET_SET_FLAGS( b->widget, GTK_CAN_DEFAULT );
+ gtk_widget_grab_default( b->widget );
+ gtk_window_set_default( GTK_WINDOW(parent->gtkwin), b->widget );
+ }
+ gtkControlGetSize( (wControl_p)b );
+ if (width == 0 && b->w < MIN_BUTTON_WIDTH && (b->option&BO_ICON)==0) {
+ b->w = MIN_BUTTON_WIDTH;
+ gtk_widget_set_size_request( b->widget, b->w, b->h );
+ }
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ gtkAddHelpString( b->widget, helpStr );
+ return b;
+}
+
+
+/*
+ *****************************************************************************
+ *
+ * Choice Boxes
+ *
+ *****************************************************************************
+ */
+
+struct wChoice_t {
+ WOBJ_COMMON
+ long *valueP;
+ wChoiceCallBack_p action;
+ int recursion;
+ };
+
+
+static long choiceGetValue(
+ wChoice_p bc )
+{
+ GList * child, * children;
+ long value, inx;
+ if (bc->type == B_TOGGLE)
+ value = 0;
+ else
+ value = -1;
+ for ( children=child=gtk_container_children(GTK_CONTAINER(bc->widget)),inx=0; child; child=child->next,inx++ ) {
+ if ( GTK_TOGGLE_BUTTON(child->data)->active ) {
+ if (bc->type == B_TOGGLE) {
+ value |= (1<<inx);
+ } else {
+ value = inx;
+ }
+ }
+ }
+ if ( children )
+ g_list_free( children );
+ return value;
+}
+
+EXPORT void wRadioSetValue(
+ wChoice_p bc, /* Radio box */
+ long value ) /* Value */
+/*
+*/
+{
+ GList * child, * children;
+ long inx;
+ for ( children=child=gtk_container_children(GTK_CONTAINER(bc->widget)),inx=0; child; child=child->next,inx++ ) {
+ if (inx == value) {
+ bc->recursion++;
+ gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(child->data), TRUE );
+ bc->recursion--;
+ }
+ }
+ if ( children )
+ g_list_free( children );
+}
+
+
+EXPORT long wRadioGetValue(
+ wChoice_p bc ) /* Radio box */
+/*
+*/
+{
+ return choiceGetValue(bc);
+}
+
+
+EXPORT void wToggleSetValue(
+ wChoice_p bc, /* Toggle box */
+ long value ) /* Values */
+/*
+*/
+{
+ GList * child, * children;
+ long inx;
+ bc->recursion++;
+ for ( children=child=gtk_container_children(GTK_CONTAINER(bc->widget)),inx=0; child; child=child->next,inx++ ) {
+ gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(child->data), (value&(1<<inx))!=0 );
+ }
+ if ( children )
+ g_list_free( children );
+ bc->recursion--;
+}
+
+
+EXPORT long wToggleGetValue(
+ wChoice_p b ) /* Toggle box */
+/*
+*/
+{
+ return choiceGetValue(b);
+}
+
+
+static int pushChoice(
+ GtkWidget *widget,
+ gpointer b )
+{
+ wChoice_p bc = (wChoice_p)b;
+ long value = choiceGetValue( bc );
+ if (debugWindow >= 2) printf("%s choice pushed = %ld\n", bc->labelStr?bc->labelStr:"No label", value );
+ if ( bc->type == B_RADIO && !(GTK_TOGGLE_BUTTON(widget))->active )
+ return 1;
+ if (bc->recursion)
+ return 1;
+ if (bc->valueP)
+ *bc->valueP = value;
+ if (bc->action)
+ bc->action( value, bc->data);
+ return 1;
+}
+
+
+static void choiceRepaint(
+ wControl_p b )
+{
+ wChoice_p bc = (wChoice_p)b;
+ if ( GTK_WIDGET_VISIBLE( b->widget ) )
+ gtkDrawBox( bc->parent, wBoxBelow, bc->realX-1, bc->realY-1, bc->w+1, bc->h+1 );
+}
+
+
+EXPORT wChoice_p wRadioCreate(
+ wWin_p parent, /* Parent window */
+ wPos_t x, /* X-position */
+ wPos_t y, /* Y-position */
+ const char * helpStr, /* Help string */
+ const char * labelStr, /* Label */
+ long option, /* Options */
+ const char **labels, /* Labels */
+ long *valueP, /* Selected value */
+ wChoiceCallBack_p action, /* Callback */
+ void *data ) /* Context */
+/*
+*/
+{
+ wChoice_p b;
+ const char ** label;
+ GtkWidget *butt0=NULL, *butt;
+
+ if ((option & BC_NOBORDER)==0) {
+ if (x>=0)
+ x++;
+ else
+ x--;
+ if (y>=0)
+ y++;
+ else
+ y--;
+ }
+ b = gtkAlloc( parent, B_RADIO, x, y, labelStr, sizeof *b, data );
+ b->option = option;
+ b->action = action;
+ b->valueP = valueP;
+ gtkComputePos( (wControl_p)b );
+
+ if (option&BC_HORZ)
+ b->widget = gtk_hbox_new( FALSE, 0 );
+ else
+ b->widget = gtk_vbox_new( FALSE, 0 );
+ if (b->widget == 0) abort();
+ for ( label=labels; *label; label++ ) {
+ butt = gtk_radio_button_new_with_label(
+ butt0?gtk_radio_button_group(GTK_RADIO_BUTTON(butt0)):NULL, _(*label) );
+ if (butt0==NULL)
+ butt0 = butt;
+ gtk_box_pack_start( GTK_BOX(b->widget), butt, TRUE, TRUE, 0 );
+ gtk_widget_show( butt );
+ gtk_signal_connect (GTK_OBJECT(butt), "toggled",
+ GTK_SIGNAL_FUNC( pushChoice ), b );
+ gtkAddHelpString( butt, helpStr );
+ }
+ if (option & BB_DEFAULT) {
+ GTK_WIDGET_SET_FLAGS( b->widget, GTK_CAN_DEFAULT );
+ gtk_widget_grab_default( b->widget );
+ /*gtk_window_set_default( GTK_WINDOW(parent->gtkwin), b->widget );*/
+ }
+ if (valueP)
+ wRadioSetValue( b, *valueP );
+
+ if ((option & BC_NOBORDER)==0) {
+ if (parent->gc == NULL) {
+ parent->gc = gdk_gc_new( parent->gtkwin->window );
+ gdk_gc_copy( parent->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+ parent->gc_linewidth = 0;
+ gdk_gc_set_line_attributes( parent->gc, parent->gc_linewidth, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ b->repaintProc = choiceRepaint;
+ b->w += 2;
+ b->h += 2;
+ }
+
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ return b;
+}
+
+wChoice_p wToggleCreate(
+ wWin_p parent, /* Parent window */
+ wPos_t x, /* X-position */
+ wPos_t y, /* Y-position */
+ const char * helpStr, /* Help string */
+ const char * labelStr, /* Label */
+ long option, /* Options */
+ const char **labels, /* Labels */
+ long *valueP, /* Selected value */
+ wChoiceCallBack_p action, /* Callback */
+ void *data ) /* Context */
+/*
+*/
+{
+ wChoice_p b;
+ const char ** label;
+ GtkWidget *butt;
+
+ if ((option & BC_NOBORDER)==0) {
+ if (x>=0)
+ x++;
+ else
+ x--;
+ if (y>=0)
+ y++;
+ else
+ y--;
+ }
+ b = gtkAlloc( parent, B_TOGGLE, x, y, labelStr, sizeof *b, data );
+ b->option = option;
+ b->action = action;
+ gtkComputePos( (wControl_p)b );
+
+ if (option&BC_HORZ)
+ b->widget = gtk_hbox_new( FALSE, 0 );
+ else
+ b->widget = gtk_vbox_new( FALSE, 0 );
+ if (b->widget == 0) abort();
+ for ( label=labels; *label; label++ ) {
+ butt = gtk_check_button_new_with_label(_(*label));
+ gtk_box_pack_start( GTK_BOX(b->widget), butt, TRUE, TRUE, 0 );
+ gtk_widget_show( butt );
+ gtk_signal_connect (GTK_OBJECT(butt), "toggled",
+ GTK_SIGNAL_FUNC( pushChoice ), b );
+ gtkAddHelpString( butt, helpStr );
+ }
+ if (valueP)
+ wToggleSetValue( b, *valueP );
+
+ if ((option & BC_NOBORDER)==0) {
+ if (parent->gc == NULL) {
+ parent->gc = gdk_gc_new( parent->gtkwin->window );
+ gdk_gc_copy( parent->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+ parent->gc_linewidth = 0;
+ gdk_gc_set_line_attributes( parent->gc, parent->gc_linewidth, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ b->repaintProc = choiceRepaint;
+ b->w += 2;
+ b->h += 2;
+ }
+
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ return b;
+}
diff --git a/app/wlib/gtklib/gtkcolor.c b/app/wlib/gtklib/gtkcolor.c
new file mode 100644
index 0000000..3856f2a
--- /dev/null
+++ b/app/wlib/gtklib/gtkcolor.c
@@ -0,0 +1,476 @@
+/** \file gtkcolor.c
+ * code for the color selection dialog and color button
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkcolor.c,v 1.3 2007-11-24 19:48:21 tshead Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "gtkint.h"
+
+#include "square10.bmp"
+
+EXPORT wDrawColor wDrawColorWhite;
+EXPORT wDrawColor wDrawColorBlack;
+
+#define RGB(R,G,B) ( ((long)(255&0xFF))<<24 | (((long)((R)&0xFF))<<16) | (((long)((G)&0xFF))<<8) | ((long)((B)&0xFF)) )
+
+#define MAX_COLOR_DISTANCE (3)
+
+typedef struct {
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+ GdkColor normalColor;
+ GdkColor invertColor;
+ long rgb;
+ int colorChar;
+ } colorMap_t;
+static GArray *colorMap_garray = NULL; // Change to use glib array
+
+static colorMap_t colorMap[] = {
+ { 255, 255, 255 }, /* White */
+ { 0, 0, 0 }, /* Black */
+ { 255, 0, 0 }, /* Red */
+ { 0, 255, 0 }, /* Green */
+ { 0, 0, 255 }, /* Blue */
+ { 255, 255, 0 }, /* Yellow */
+ { 255, 0, 255 }, /* Purple */
+ { 0, 255, 255 }, /* Aqua */
+ { 128, 0, 0 }, /* Dk. Red */
+ { 0, 128, 0 }, /* Dk. Green */
+ { 0, 0, 128 }, /* Dk. Blue */
+ { 128, 128, 0 }, /* Dk. Yellow */
+ { 128, 0, 128 }, /* Dk. Purple */
+ { 0, 128, 128 }, /* Dk. Aqua */
+ { 65, 105, 225 }, /* Royal Blue */
+ { 0, 191, 255 }, /* DeepSkyBlue */
+ { 125, 206, 250 }, /* LightSkyBlue */
+ { 70, 130, 180 }, /* Steel Blue */
+ { 176, 224, 230 }, /* Powder Blue */
+ { 127, 255, 212 }, /* Aquamarine */
+ { 46, 139, 87 }, /* SeaGreen */
+ { 152, 251, 152 }, /* PaleGreen */
+ { 124, 252, 0 }, /* LawnGreen */
+ { 50, 205, 50 }, /* LimeGreen */
+ { 34, 139, 34 }, /* ForestGreen */
+ { 255, 215, 0 }, /* Gold */
+ { 188, 143, 143 }, /* RosyBrown */
+ { 139, 69, 19 }, /* SaddleBrown */
+ { 245, 245, 220 }, /* Beige */
+ { 210, 180, 140 }, /* Tan */
+ { 210, 105, 30 }, /* Chocolate */
+ { 165, 42, 42 }, /* Brown */
+ { 255, 165, 0 }, /* Orange */
+ { 255, 127, 80 }, /* Coral */
+ { 255, 99, 71 }, /* Tomato */
+ { 255, 105, 180 }, /* HotPink */
+ { 255, 192, 203 }, /* Pink */
+ { 176, 48, 96 }, /* Maroon */
+ { 238, 130, 238 }, /* Violet */
+ { 160, 32, 240 }, /* Purple */
+ { 16, 16, 16 }, /* Gray */
+ { 32, 32, 32 }, /* Gray */
+ { 48, 48, 48 }, /* Gray */
+ { 64, 64, 64 }, /* Gray */
+ { 80, 80, 80 }, /* Gray */
+ { 96, 96, 96 }, /* Gray */
+ { 112, 112, 122 }, /* Gray */
+ { 128, 128, 128 }, /* Gray */
+ { 144, 144, 144 }, /* Gray */
+ { 160, 160, 160 }, /* Gray */
+ { 176, 176, 176 }, /* Gray */
+ { 192, 192, 192 }, /* Gray */
+ { 208, 208, 208 }, /* Gray */
+ { 224, 224, 224 }, /* Gray */
+ { 240, 240, 240 }, /* Gray */
+ { 0, 0, 0 } /* BlackPixel */
+ };
+
+#define NUM_GRAYS (16)
+
+static GdkColormap * gtkColorMap;
+
+static char lastColorChar = '!';
+
+/*****************************************************************************
+ *
+ *
+ *
+ */
+
+
+EXPORT wDrawColor wDrawColorGray(
+ int percent )
+{
+ int n;
+ long rgb;
+ n = (percent * (NUM_GRAYS+1)) / 100;
+ if ( n <= 0 )
+ return wDrawColorBlack;
+ else if ( n > NUM_GRAYS )
+ return wDrawColorWhite;
+ else {
+ n = (n*256)/NUM_GRAYS;
+ rgb = RGB( n, n, n );
+ return wDrawFindColor( rgb );
+ }
+}
+
+
+void gtkGetColorMap( void )
+{
+ if (gtkColorMap)
+ return;
+ gtkColorMap = gtk_widget_get_colormap( gtkMainW->widget );
+ return;
+}
+
+void init_colorMapValue( colorMap_t * t) {
+
+ t->rgb = RGB( t->red, t->green, t->blue );
+ t->normalColor.red = t->red*65535/255;
+ t->normalColor.green = t->green*65535/255;
+ t->normalColor.blue = t->blue*65535/255;
+ gdk_color_alloc( gtkColorMap, &t->normalColor );
+ t->invertColor = t->normalColor;
+ t->invertColor.pixel ^= g_array_index(colorMap_garray, colorMap_t, wDrawColorWhite).normalColor.pixel;
+ t->colorChar = lastColorChar++;
+ if (lastColorChar >= 0x7F)
+ lastColorChar = '!'+1;
+ else if (lastColorChar == '"')
+ lastColorChar++;
+
+}
+
+
+void init_colorMap( void )
+{
+ colorMap_garray = g_array_sized_new(TRUE, TRUE, sizeof(colorMap_t), sizeof(colorMap)/sizeof(colorMap_t));
+ g_array_append_vals(colorMap_garray, &colorMap, sizeof(colorMap)/sizeof(colorMap_t));
+
+ int gint;
+
+ for(gint=0; gint<colorMap_garray->len; gint++) {
+ init_colorMapValue(&g_array_index(colorMap_garray, colorMap_t, gint));
+ }
+}
+
+
+EXPORT wDrawColor wDrawFindColor(
+ long rgb0 )
+{
+ wDrawColor cc;
+ int r0, g0, b0;
+ int d0, d1;
+ long rgb1;
+ colorMap_t * cm_p;
+
+ gtkGetColorMap();
+
+ cc = wDrawColorBlack;
+ r0 = (int)(rgb0>>16)&0xFF;
+ g0 = (int)(rgb0>>8)&0xFF;
+ b0 = (int)(rgb0)&0xFF;
+ d0 = 256*3;
+
+ // Initialize garray if needed
+ if (colorMap_garray == NULL) {
+ init_colorMap();
+ }
+
+ int gint;
+
+ // Iterate over entire garray
+ for (gint=0; gint<colorMap_garray->len; gint++) {
+ cm_p = &g_array_index(colorMap_garray, colorMap_t, gint);
+ rgb1 = cm_p->rgb;
+ d1 = abs(r0-cm_p->red) + abs(g0-cm_p->green) + abs(b0-cm_p->blue);
+ if (d1 == 0)
+ return gint;
+ if (d1 < d0) {
+ d0 = d1;
+ cc = gint;
+ }
+ }
+ if (d0 <= MAX_COLOR_DISTANCE) {
+ return cc;
+ }
+ // No good value - so add one
+ colorMap_t tempMapValue;
+ //DYNARR_APPEND( colorMap_t, colorMap_da, 10 );
+ tempMapValue.red = r0;
+ tempMapValue.green = g0;
+ tempMapValue.blue = b0;
+ init_colorMapValue(&tempMapValue);
+ g_array_append_val(colorMap_garray,tempMapValue);
+ return gint;
+}
+
+
+EXPORT long wDrawGetRGB(
+ wDrawColor color )
+{
+ gtkGetColorMap();
+
+ if(colorMap_garray == NULL)
+ init_colorMap();
+
+ if (color < 0 || color > colorMap_garray->len)
+ abort();
+ colorMap_t * colorMap_e;
+ colorMap_e = &g_array_index(colorMap_garray, colorMap_t, color);
+ return colorMap_e->rgb;
+}
+
+
+EXPORT GdkColor* gtkGetColor(
+ wDrawColor color,
+ wBool_t normal )
+{
+ gtkGetColorMap();
+
+ if(colorMap_garray == NULL)
+ init_colorMap();
+
+ if (color < 0 || color > colorMap_garray->len)
+ abort();
+ colorMap_t * colorMap_e;
+ colorMap_e = &g_array_index(colorMap_garray, colorMap_t, color);
+
+ if ( normal )
+ return &colorMap_e->normalColor;
+ else
+ return &colorMap_e->invertColor;
+}
+
+
+EXPORT int gtkGetColorChar(
+ wDrawColor color )
+{
+ /*gtkGetColorMap();*/
+ if(colorMap_garray == NULL)
+ init_colorMap();
+
+ if (color < 0 || color > colorMap_garray->len)
+ abort();
+ colorMap_t * colorMap_e;
+ colorMap_e = &g_array_index(colorMap_garray, colorMap_t, color);
+ return colorMap_e->colorChar;
+}
+
+
+EXPORT int gtkMapPixel(
+ long pixel )
+{
+ colorMap_t * mapValue;
+ int gint;
+
+ if(colorMap_garray == NULL)
+ init_colorMap();
+
+ for (gint=0; gint<colorMap_garray->len; gint++ ) {
+ mapValue = &g_array_index(colorMap_garray, colorMap_t, gint);
+ if ( mapValue->normalColor.pixel == pixel ) {
+ return mapValue->colorChar;
+ }
+ }
+ mapValue = &g_array_index(colorMap_garray, colorMap_t, wDrawColorBlack);
+ return mapValue->colorChar;
+}
+
+
+/*
+ *****************************************************************************
+ *
+ * Color Selection Dialog
+ *
+ *****************************************************************************
+ */
+
+
+static int colorSelectValid;
+static int colorSelectOk(
+ GtkWidget * widget,
+ GtkWidget * * window )
+{
+ gtkDoModal( NULL, FALSE );
+ gtk_widget_hide( GTK_WIDGET(*window) );
+ colorSelectValid = TRUE;
+ return FALSE;
+}
+
+
+static int colorSelectCancel(
+ GtkWidget * widget,
+ GtkWidget * * window )
+{
+ gtkDoModal( NULL, FALSE );
+ gtk_widget_hide( GTK_WIDGET(*window) );
+ colorSelectValid = FALSE;
+ if (widget == *window)
+ /* Called by destroy event, window is gone */
+ *window = NULL;
+ return FALSE;
+}
+
+
+EXPORT wBool_t wColorSelect(
+ const char * title,
+ wDrawColor * color )
+{
+ static GtkWidget * colorSelectD = NULL;
+ long rgb;
+ gdouble colors[4]; // Remember opacity!
+
+ if (colorSelectD == NULL) {
+ colorSelectD = gtk_color_selection_dialog_new( title );
+ gtk_signal_connect( GTK_OBJECT(GTK_COLOR_SELECTION_DIALOG(colorSelectD)->ok_button), "clicked", (GtkSignalFunc)colorSelectOk, (gpointer)&colorSelectD );
+ gtk_signal_connect( GTK_OBJECT(GTK_COLOR_SELECTION_DIALOG(colorSelectD)->cancel_button), "clicked", (GtkSignalFunc)colorSelectCancel, (gpointer)&colorSelectD );
+ gtk_signal_connect( GTK_OBJECT(colorSelectD), "destroy", (GtkSignalFunc)colorSelectCancel, (gpointer)&colorSelectD );
+ } else {
+ gtk_window_set_title( GTK_WINDOW(colorSelectD), title );
+ }
+
+ colorMap_t * colorMap_e;
+
+ if (!colorMap_garray) {
+ init_colorMap();
+ }
+
+ colorMap_e = &g_array_index(colorMap_garray, colorMap_t, *color);
+ colors[0] = colorMap_e->red/255.0;
+ colors[1] = colorMap_e->green/255.0;
+ colors[2] = colorMap_e->blue/255.0;
+ colors[3] = 1.0; // Override to Fully opaque
+ gtk_color_selection_set_color( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorSelectD)->colorsel), colors );
+ gtk_widget_show( colorSelectD );
+ gtkDoModal( NULL, TRUE );
+ if (colorSelectValid) {
+ gtk_color_selection_get_color( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorSelectD)->colorsel), colors );
+ rgb = RGB( (int)(colors[0]*255), (int)(colors[1]*255), (int)(colors[2]*255) );
+ * color = wDrawFindColor( rgb );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ *****************************************************************************
+ *
+ * Color Selection Button
+ *
+ *****************************************************************************
+ */
+
+typedef struct {
+ wDrawColor * valueP;
+ wColorSelectButtonCallBack_p action;
+ const char * labelStr;
+ void * data;
+ wDrawColor color;
+ wButton_p button;
+ } 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 );
+ }
+}
+
+
+void wColorSelectButtonSetColor(
+ wButton_p bb,
+ wDrawColor color )
+{
+ wIcon_p bm;
+ bm = wIconCreateBitMap( square10_width, square10_height, square10_bits, color );
+ wButtonSetLabel( bb, (const char*)bm );
+ ((colorData_t*)((wControl_p)bb)->data)->color = color;
+}
+
+
+wDrawColor wColorSelectButtonGetColor(
+ wButton_p bb )
+{
+ return ((colorData_t*)((wControl_p)bb)->data)->color;
+}
+
+/** Create the button showing the current paint color and starting the color selection dialog.
+ * \param IN parent parent window
+ * \param IN x x coordinate
+ * \param IN Y y coordinate
+ * \param IN helpStr balloon help string
+ * \param IN labelStr Button label ???
+ * \param IN option
+ * \param IN width
+ * \param IN valueP Current color ???
+ * \param IN action Button callback procedure
+ * \param IN data ???
+ * \return bb handle for created button
+ */
+
+wButton_p wColorSelectButtonCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ long option,
+ wPos_t width,
+ wDrawColor *valueP,
+ wColorSelectButtonCallBack_p action,
+ void * data )
+{
+ wButton_p bb;
+ wIcon_p bm;
+ colorData_t * cd;
+ bm = wIconCreateBitMap( square10_width, square10_height, square10_bits, (valueP?*valueP:0) );
+ cd = malloc( sizeof( colorData_t ));
+ cd->valueP = valueP;
+ cd->action = action;
+ cd->data = data;
+ cd->labelStr = labelStr;
+ cd->color = (valueP?*valueP:0);
+ bb = wButtonCreate( parent, x, y, helpStr, (const char*)bm, option|BO_ICON, width, doColorButton, cd );
+ cd->button = bb;
+ if (labelStr)
+ ((wControl_p)bb)->labelW = gtkAddLabel( (wControl_p)bb, labelStr );
+ return bb;
+}
diff --git a/app/wlib/gtklib/gtkdraw-cairo.c b/app/wlib/gtklib/gtkdraw-cairo.c
new file mode 100644
index 0000000..e9b6447
--- /dev/null
+++ b/app/wlib/gtklib/gtkdraw-cairo.c
@@ -0,0 +1,1212 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkdraw-cairo.c,v 1.11 2009-10-03 17:34:37 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+
+#include "gtkint.h"
+#include "gdk/gdkkeysyms.h"
+
+
+#define CENTERMARK_LENGTH (6)
+
+static long drawVerbose = 0;
+
+struct wDrawBitMap_t {
+ int w;
+ int h;
+ int x;
+ int y;
+ const char * bits;
+ GdkPixmap * pixmap;
+ GdkBitmap * mask;
+ };
+
+struct wDraw_t {
+ WOBJ_COMMON
+ void * context;
+ wDrawActionCallBack_p action;
+ wDrawRedrawCallBack_p redraw;
+
+ GdkPixmap * pixmap;
+ GdkPixmap * pixmapBackup;
+
+ double dpi;
+
+ GdkGC * gc;
+ wDrawWidth lineWidth;
+ wDrawOpts opts;
+ wPos_t maxW;
+ wPos_t maxH;
+ unsigned long lastColor;
+ wBool_t lastColorInverted;
+ const char * helpStr;
+
+ wPos_t lastX;
+ wPos_t lastY;
+
+ wBool_t delayUpdate;
+ };
+
+struct wDraw_t psPrint_d;
+
+/*****************************************************************************
+ *
+ * MACROS
+ *
+ */
+
+#define LBORDER (22)
+#define RBORDER (6)
+#define TBORDER (6)
+#define BBORDER (20)
+
+#define INMAPX(D,X) (X)
+#define INMAPY(D,Y) (((D)->h-1) - (Y))
+#define OUTMAPX(D,X) (X)
+#define OUTMAPY(D,Y) (((D)->h-1) - (Y))
+
+
+/*******************************************************************************
+ *
+ * Basic Drawing Functions
+ *
+*******************************************************************************/
+
+
+
+static GdkGC * selectGC(
+ wDraw_p bd,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ if(width < 0.0)
+ {
+ width = - width;
+ }
+
+ if(opts & wDrawOptTemp)
+ {
+ if(bd->lastColor != color || !bd->lastColorInverted)
+ {
+ gdk_gc_set_foreground( bd->gc, gtkGetColor(color,FALSE) );
+ bd->lastColor = color;
+ bd->lastColorInverted = TRUE;
+ }
+ gdk_gc_set_function( bd->gc, GDK_XOR );
+ gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ else
+ {
+ if(bd->lastColor != color || bd->lastColorInverted)
+ {
+ gdk_gc_set_foreground( bd->gc, gtkGetColor(color,TRUE) );
+ bd->lastColor = color;
+ bd->lastColorInverted = FALSE;
+ }
+ gdk_gc_set_function( bd->gc, GDK_COPY );
+ if (lineType==wDrawLineDash)
+ {
+ gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ else
+ {
+ gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+
+ gdk_gc_set_function(bd->gc, GDK_NOOP);
+ }
+ return bd->gc;
+}
+
+static cairo_t* gtkDrawCreateCairoContext(
+ wDraw_p bd,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ cairo_t* cairo = gdk_cairo_create(bd->pixmap);
+
+ width = width ? abs(width) : 1;
+ cairo_set_line_width(cairo, width);
+
+ cairo_set_line_cap(cairo, CAIRO_LINE_CAP_BUTT);
+ cairo_set_line_join(cairo, CAIRO_LINE_JOIN_MITER);
+
+ switch(lineType)
+ {
+ case wDrawLineSolid:
+ {
+ cairo_set_dash(cairo, 0, 0, 0);
+ break;
+ }
+ case wDrawLineDash:
+ {
+ double dashes[] = { 5, 5 };
+ cairo_set_dash(cairo, dashes, 2, 0);
+ break;
+ }
+ }
+
+ if(opts & wDrawOptTemp)
+ {
+ cairo_set_source_rgba(cairo, 0, 0, 0, 0);
+ }
+ else
+ {
+ GdkColor* const gcolor = gtkGetColor(color, TRUE);
+ cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0);
+
+ cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
+ }
+
+ return cairo;
+}
+
+static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {
+ cairo_destroy(cairo);
+}
+
+EXPORT void wDrawDelayUpdate(
+ wDraw_p bd,
+ wBool_t delay )
+{
+ GdkRectangle update_rect;
+
+ if ( (!delay) && bd->delayUpdate ) {
+ update_rect.x = 0;
+ update_rect.y = 0;
+ update_rect.width = bd->w;
+ update_rect.height = bd->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+ }
+ bd->delayUpdate = delay;
+}
+
+
+EXPORT void wDrawLine(
+ wDraw_p bd,
+ wPos_t x0, wPos_t y0,
+ wPos_t x1, wPos_t y1,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintLine( x0, y0, x1, y1, width, lineType, color, opts );
+ return;
+ }
+ gc = selectGC( bd, width, lineType, color, opts );
+ x0 = INMAPX(bd,x0);
+ y0 = INMAPY(bd,y0);
+ x1 = INMAPX(bd,x1);
+ y1 = INMAPY(bd,y1);
+ gdk_draw_line( bd->pixmap, gc, x0, y0, x1, y1 );
+
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts);
+ cairo_move_to(cairo, x0 + 0.5, y0 + 0.5);
+ cairo_line_to(cairo, x1 + 0.5, y1 + 0.5);
+ cairo_stroke(cairo);
+ gtkDrawDestroyCairoContext(cairo);
+
+ if ( bd->delayUpdate || bd->widget == NULL ) return;
+ width /= 2;
+ if (x0 < x1) {
+ update_rect.x = x0-1-width;
+ update_rect.width = x1-x0+2+width+width;
+ } else {
+ update_rect.x = x1-1-width;
+ update_rect.width = x0-x1+2+width+width;
+ }
+ if (y0 < y1) {
+ update_rect.y = y0-1-width;
+ update_rect.height = y1-y0+2+width+width;
+ } else {
+ update_rect.y = y1-1-width;
+ update_rect.height = y0-y1+2+width+width;
+ }
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+/**
+ * Draw an arc around a specified center
+ *
+ * \param bd IN ?
+ * \param x0, y0 IN center of arc
+ * \param r IN radius
+ * \param angle0, angle1 IN start and end angle
+ * \param drawCenter draw marking for center
+ * \param width line width
+ * \param lineType
+ * \param color color
+ * \param opts ?
+ */
+
+
+EXPORT void wDrawArc(
+ wDraw_p bd,
+ wPos_t x0, wPos_t y0,
+ wPos_t r,
+ wAngle_t angle0,
+ wAngle_t angle1,
+ int drawCenter,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ int x, y, w, h;
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );
+ return;
+ }
+ gc = selectGC( bd, width, lineType, color, opts );
+ if (r < 6.0/75.0) return;
+ x = INMAPX(bd,x0-r);
+ y = INMAPY(bd,y0+r);
+ w = 2*r;
+ h = 2*r;
+
+ // remove the old arc
+ gdk_draw_arc( bd->pixmap, gc, FALSE, x, y, w, h, (int)((-angle0 + 90)*64.0), (int)(-angle1*64.0) );
+
+ // and its center point
+ if (drawCenter) {
+ x = INMAPX(bd,x0);
+ y = INMAPY(bd,y0);
+ gdk_draw_line( bd->pixmap, gc, x - ( CENTERMARK_LENGTH/2), y, x + ( CENTERMARK_LENGTH/2), y );
+ gdk_draw_line( bd->pixmap, gc, x, y - ( CENTERMARK_LENGTH/2), x, y + ( CENTERMARK_LENGTH/2));
+ }
+
+ // now create the new arc
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts);
+ cairo_new_path(cairo);
+
+ // its center point marker
+ if(drawCenter)
+ {
+ // draw a small crosshair to mark the center of the curve
+ cairo_move_to(cairo, INMAPX(bd, x0 - (CENTERMARK_LENGTH / 2)), INMAPY(bd, y0 ));
+ cairo_line_to(cairo, INMAPX(bd, x0 + (CENTERMARK_LENGTH / 2)), INMAPY(bd, y0 ));
+ cairo_move_to(cairo, INMAPX(bd, x0), INMAPY(bd, y0 - (CENTERMARK_LENGTH / 2 )));
+ cairo_line_to(cairo, INMAPX(bd, x0) , INMAPY(bd, y0 + (CENTERMARK_LENGTH / 2)));
+ cairo_new_sub_path( cairo );
+ }
+
+ // draw the curve itself
+ cairo_arc_negative(cairo, INMAPX(bd, x0), INMAPY(bd, y0), r, (angle0 - 90 + angle1) * (M_PI / 180.0), (angle0 - 90) * (M_PI / 180.0));
+ cairo_stroke(cairo);
+
+ gtkDrawDestroyCairoContext(cairo);
+
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ width /= 2;
+ update_rect.x = x-1-width;
+ update_rect.y = y-1-width;
+ update_rect.width = w+2+width+width;
+ update_rect.height = h+2+width+width;
+ gtk_widget_draw( bd->widget, &update_rect );
+
+}
+
+EXPORT void wDrawPoint(
+ wDraw_p bd,
+ wPos_t x0, wPos_t y0,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ /*psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );*/
+ return;
+ }
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opts );
+ gdk_draw_point( bd->pixmap, gc, INMAPX(bd, x0 ), INMAPY(bd, y0 ) );
+
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts);
+ cairo_new_path(cairo);
+ cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), 0.75, 0, 2 * M_PI);
+ cairo_stroke(cairo);
+ gtkDrawDestroyCairoContext(cairo);
+
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = INMAPX(bd, x0 )-1;
+ update_rect.y = INMAPY(bd, y0 )-1;
+ update_rect.width = 2;
+ update_rect.height = 2;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+/*******************************************************************************
+ *
+ * Strings
+ *
+ ******************************************************************************/
+
+EXPORT void wDrawString(
+ wDraw_p bd,
+ wPos_t x, wPos_t y,
+ wAngle_t a,
+ const char * s,
+ wFont_p fp,
+ wFontSize_t fs,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ PangoLayout *layout;
+ GdkRectangle update_rect;
+ int w;
+ int h;
+ gint ascent;
+ gint descent;
+ double angle = -M_PI * a / 180.0;
+
+ if ( bd == &psPrint_d ) {
+ psPrintString( x, y, a, (char *) s, fp, fs, color, opts );
+ return;
+ }
+
+ x = INMAPX(bd,x);
+ y = INMAPY(bd,y);
+
+ /* draw text */
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts);
+
+ cairo_save( cairo );
+ cairo_translate( cairo, x, y );
+ cairo_rotate( cairo, angle );
+
+ layout = gtkFontCreatePangoLayout(bd->widget, cairo, fp, fs, s,
+ (int *) &w, (int *) &h,
+ (int *) &ascent, (int *) &descent);
+
+ /* cairo does not support the old method of text removal by overwrite; force always write here and
+ refresh on cancel event */
+ GdkColor* const gcolor = gtkGetColor(color, TRUE);
+ cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0);
+
+ cairo_move_to( cairo, 0, -ascent );
+
+ pango_cairo_show_layout(cairo, layout);
+ gtkFontDestroyPangoLayout(layout);
+ cairo_restore( cairo );
+ gtkDrawDestroyCairoContext(cairo);
+
+ if (bd->delayUpdate || bd->widget == NULL) return;
+
+ /* recalculate the area to be updated
+ * for simplicity sake I added plain text height ascent and descent,
+ * mathematically correct would be to use the trigonometrical functions as well
+ */
+ update_rect.x = (gint) x - ascent - descent - 1;
+ update_rect.y = (gint) y - (gint) ascent - 1;
+ update_rect.width = (gint) (w * cos( angle ) + 2 + ascent + descent);
+ update_rect.height = (gint) (w * sin( angle ) + ascent + descent + 2 );
+ gtk_widget_draw(bd->widget, &update_rect);
+}
+
+EXPORT void wDrawGetTextSize(
+ wPos_t *w,
+ wPos_t *h,
+ wPos_t *d,
+ wDraw_p bd,
+ const char * s,
+ wFont_p fp,
+ wFontSize_t fs )
+{
+ int textWidth;
+ int textHeight;
+ int ascent;
+ int descent;
+
+ *w = 0;
+ *h = 0;
+
+ gtkFontDestroyPangoLayout(
+ gtkFontCreatePangoLayout(bd->widget, NULL, fp, fs, s,
+ &textWidth, (int *) &textHeight,
+ (int *) &ascent, (int *) &descent));
+
+ *w = (wPos_t) textWidth;
+ *h = (wPos_t) ascent;
+ *d = (wPos_t) descent;
+
+ if (debugWindow >= 3)
+ fprintf(stderr, "text metrics: w=%d, h=%d, d=%d\n", *w, *h, *d);
+}
+
+
+/*******************************************************************************
+ *
+ * Basic Drawing Functions
+ *
+*******************************************************************************/
+
+EXPORT void wDrawFilledRectangle(
+ wDraw_p bd,
+ wPos_t x,
+ wPos_t y,
+ wPos_t w,
+ wPos_t h,
+ wDrawColor color,
+ wDrawOpts opt )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintFillRectangle( x, y, w, h, color, opt );
+ return;
+ }
+
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
+ x = INMAPX(bd,x);
+ y = INMAPY(bd,y)-h;
+ gdk_draw_rectangle( bd->pixmap, gc, TRUE, x, y, w, h );
+
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt);
+
+ cairo_move_to(cairo, x, y);
+ cairo_rel_line_to(cairo, w, 0);
+ cairo_rel_line_to(cairo, 0, h);
+ cairo_rel_line_to(cairo, -w, 0);
+ cairo_fill(cairo);
+ gtkDrawDestroyCairoContext(cairo);
+
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = x-1;
+ update_rect.y = y-1;
+ update_rect.width = w+2;
+ update_rect.height = h+2;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+EXPORT void wDrawFilledPolygon(
+ wDraw_p bd,
+ wPos_t p[][2],
+ int cnt,
+ wDrawColor color,
+ wDrawOpts opt )
+{
+ GdkGC * gc;
+ static int maxCnt = 0;
+ static GdkPoint *points;
+ int i;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintFillPolygon( p, cnt, color, opt );
+ return;
+ }
+
+ if (cnt > maxCnt) {
+ if (points == NULL)
+ points = (GdkPoint*)malloc( cnt*sizeof *points );
+ else
+ points = (GdkPoint*)realloc( points, cnt*sizeof *points );
+ if (points == NULL)
+ abort();
+ maxCnt = cnt;
+ }
+
+ update_rect.x = bd->w;
+ update_rect.y = bd->h;
+ update_rect.width = 0;
+ update_rect.height = 0;
+ for (i=0; i<cnt; i++) {
+ points[i].x = INMAPX(bd,p[i][0]);
+ points[i].y = INMAPY(bd,p[i][1]);
+ if (update_rect.x > points[i].x)
+ update_rect.x = points[i].x;
+ if (update_rect.width < points[i].x)
+ update_rect.width = points[i].x;
+ if (update_rect.y > points[i].y)
+ update_rect.y = points[i].y;
+ if (update_rect.height < points[i].y)
+ update_rect.height = points[i].y;
+ }
+ update_rect.x -= 1;
+ update_rect.y -= 1;
+ update_rect.width -= update_rect.x-2;
+ update_rect.height -= update_rect.y-2;
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
+ gdk_draw_polygon( bd->pixmap, gc, TRUE, points, cnt );
+
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt);
+ for(i = 0; i < cnt; ++i)
+ {
+ if(i)
+ cairo_line_to(cairo, points[i].x, points[i].y);
+ else
+ cairo_move_to(cairo, points[i].x, points[i].y);
+ }
+ cairo_fill(cairo);
+ gtkDrawDestroyCairoContext(cairo);
+
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+EXPORT void wDrawFilledCircle(
+ wDraw_p bd,
+ wPos_t x0,
+ wPos_t y0,
+ wPos_t r,
+ wDrawColor color,
+ wDrawOpts opt )
+{
+ GdkGC * gc;
+ int x, y, w, h;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintFillCircle( x0, y0, r, color, opt );
+ return;
+ }
+
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
+ x = INMAPX(bd,x0-r);
+ y = INMAPY(bd,y0+r);
+ w = 2*r;
+ h = 2*r;
+ gdk_draw_arc( bd->pixmap, gc, TRUE, x, y, w, h, 0, 360*64 );
+
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt);
+ cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), r, 0, 2 * M_PI);
+ cairo_fill(cairo);
+ gtkDrawDestroyCairoContext(cairo);
+
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = x-1;
+ update_rect.y = y-1;
+ update_rect.width = w+2;
+ update_rect.height = h+2;
+ gtk_widget_draw( bd->widget, &update_rect );
+
+}
+
+
+EXPORT void wDrawClear(
+ wDraw_p bd )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ gc = selectGC( bd, 0, wDrawLineSolid, wDrawColorWhite, 0 );
+ gdk_draw_rectangle(bd->pixmap, gc, TRUE, 0, 0, bd->w, bd->h);
+
+ cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, wDrawColorWhite, 0);
+ cairo_move_to(cairo, 0, 0);
+ cairo_rel_line_to(cairo, bd->w, 0);
+ cairo_rel_line_to(cairo, 0, bd->h);
+ cairo_rel_line_to(cairo, -bd->w, 0);
+ cairo_fill(cairo);
+ gtkDrawDestroyCairoContext(cairo);
+
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = 0;
+ update_rect.y = 0;
+ update_rect.width = bd->w;
+ update_rect.height = bd->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+EXPORT void * wDrawGetContext(
+ wDraw_p bd )
+{
+ return bd->context;
+}
+
+/*******************************************************************************
+ *
+ * Bit Maps
+ *
+*******************************************************************************/
+
+
+EXPORT wDrawBitMap_p wDrawBitMapCreate(
+ wDraw_p bd,
+ int w,
+ int h,
+ int x,
+ int y,
+ const char * fbits )
+{
+ wDrawBitMap_p bm;
+
+ bm = (wDrawBitMap_p)malloc( sizeof *bm );
+ bm->w = w;
+ bm->h = h;
+ /*bm->pixmap = gtkMakeIcon( NULL, fbits, w, h, wDrawColorBlack, &bm->mask );*/
+ bm->bits = fbits;
+ bm->x = x;
+ bm->y = y;
+ return bm;
+}
+
+
+EXPORT void wDrawBitMap(
+ wDraw_p bd,
+ wDrawBitMap_p bm,
+ wPos_t x, wPos_t y,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+ int i, j, wb;
+ wPos_t xx, yy;
+ wControl_p b;
+ GdkDrawable * gdk_window;
+
+ x = INMAPX( bd, x-bm->x );
+ y = INMAPY( bd, y-bm->y )-bm->h;
+ wb = (bm->w+7)/8;
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opts );
+
+ for ( i=0; i<bm->w; i++ )
+ for ( j=0; j<bm->h; j++ )
+ if ( bm->bits[ j*wb+(i>>3) ] & (1<<(i&07)) ) {
+ xx = x+i;
+ yy = y+j;
+ if ( 0 <= xx && xx < bd->w &&
+ 0 <= yy && yy < bd->h ) {
+ gdk_window = bd->pixmap;
+ b = (wControl_p)bd;
+ } else if ( (opts&wDrawOptNoClip) != 0 ) {
+ xx += bd->realX;
+ yy += bd->realY;
+ b = gtkGetControlFromPos( bd->parent, xx, yy );
+ if ( b ) {
+ if ( b->type == B_DRAW )
+ gdk_window = ((wDraw_p)b)->pixmap;
+ else
+ gdk_window = b->widget->window;
+ xx -= b->realX;
+ yy -= b->realY;
+ } else {
+ gdk_window = bd->parent->widget->window;
+ }
+ } else {
+ continue;
+ }
+/*printf( "gdk_draw_point( %ld, gc, %d, %d )\n", (long)gdk_window, xx, yy );*/
+ gdk_draw_point( gdk_window, gc, xx, yy );
+ if ( b && b->type == B_DRAW ) {
+ update_rect.x = xx-1;
+ update_rect.y = yy-1;
+ update_rect.width = 3;
+ update_rect.height = 3;
+ gtk_widget_draw( b->widget, &update_rect );
+ }
+ }
+#ifdef LATER
+ gdk_draw_pixmap(bd->pixmap, gc,
+ bm->pixmap,
+ 0, 0,
+ x, y,
+ bm->w, bm->h );
+#endif
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+
+ update_rect.x = x;
+ update_rect.y = y;
+ update_rect.width = bm->w;
+ update_rect.height = bm->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+
+/*******************************************************************************
+ *
+ * Event Handlers
+ *
+*******************************************************************************/
+
+
+
+EXPORT void wDrawSaveImage(
+ wDraw_p bd )
+{
+ if ( bd->pixmapBackup ) {
+ gdk_pixmap_unref( bd->pixmapBackup );
+ }
+ bd->pixmapBackup = gdk_pixmap_new( bd->widget->window, bd->w, bd->h, -1 );
+
+ selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 );
+ gdk_gc_set_function(bd->gc, GDK_COPY);
+
+ gdk_draw_pixmap( bd->pixmapBackup, bd->gc,
+ bd->pixmap,
+ 0, 0,
+ 0, 0,
+ bd->w, bd->h );
+}
+
+
+EXPORT void wDrawRestoreImage(
+ wDraw_p bd )
+{
+ GdkRectangle update_rect;
+ if ( bd->pixmapBackup ) {
+
+ selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 );
+ gdk_gc_set_function(bd->gc, GDK_COPY);
+
+ gdk_draw_pixmap( bd->pixmap, bd->gc,
+ bd->pixmapBackup,
+ 0, 0,
+ 0, 0,
+ bd->w, bd->h );
+
+ if ( bd->delayUpdate || bd->widget == NULL ) return;
+ update_rect.x = 0;
+ update_rect.y = 0;
+ update_rect.width = bd->w;
+ update_rect.height = bd->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+ }
+}
+
+
+EXPORT void wDrawSetSize(
+ wDraw_p bd,
+ wPos_t w,
+ wPos_t h )
+{
+ wBool_t repaint;
+ if (bd == NULL) {
+ fprintf(stderr,"resizeDraw: no client data\n");
+ return;
+ }
+
+ /* Negative values crashes the program */
+ if (w < 0 || h < 0)
+ return;
+
+ repaint = (w != bd->w || h != bd->h);
+ bd->w = w;
+ bd->h = h;
+ gtk_widget_set_size_request( bd->widget, w, h );
+ if (repaint)
+ {
+ if (bd->pixmap)
+ gdk_pixmap_unref( bd->pixmap );
+ bd->pixmap = gdk_pixmap_new( bd->widget->window, w, h, -1 );
+
+ wDrawClear( bd );
+ /*bd->redraw( bd, bd->context, w, h );*/
+ }
+ /*wRedraw( bd );*/
+}
+
+
+EXPORT void wDrawGetSize(
+ wDraw_p bd,
+ wPos_t *w,
+ wPos_t *h )
+{
+ if (bd->widget)
+ gtkControlGetSize( (wControl_p)bd );
+ *w = bd->w-2;
+ *h = bd->h-2;
+}
+
+
+EXPORT double wDrawGetDPI(
+ wDraw_p d )
+{
+ if (d == &psPrint_d)
+ return 1440.0;
+ else
+ return d->dpi;
+}
+
+
+EXPORT double wDrawGetMaxRadius(
+ wDraw_p d )
+{
+ if (d == &psPrint_d)
+ return 10e9;
+ else
+ return 32767.0;
+}
+
+
+EXPORT void wDrawClip(
+ wDraw_p d,
+ wPos_t x,
+ wPos_t y,
+ wPos_t w,
+ wPos_t h )
+{
+ GdkRectangle rect;
+ rect.width = w;
+ rect.height = h;
+ rect.x = INMAPX( d, x );
+ rect.y = INMAPY( d, y ) - rect.height;
+ gdk_gc_set_clip_rectangle( d->gc, &rect );
+
+}
+
+
+static gint draw_expose_event(
+ GtkWidget *widget,
+ GdkEventExpose *event,
+ wDraw_p bd)
+{
+ gdk_draw_pixmap(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ bd->pixmap,
+ event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ return FALSE;
+}
+
+
+static gint draw_configure_event(
+ GtkWidget *widget,
+ GdkEventConfigure *event,
+ wDraw_p bd)
+{
+ return FALSE;
+}
+
+static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown" };
+
+/**
+ * Handler for scroll events, ie mouse wheel activity
+ */
+
+static gint draw_scroll_event(
+ GtkWidget *widget,
+ GdkEventScroll *event,
+ wDraw_p bd)
+{
+ wAction_t action;
+
+ switch( event->direction ) {
+ case GDK_SCROLL_UP:
+ action = wActionWheelUp;
+ break;
+ case GDK_SCROLL_DOWN:
+ action = wActionWheelDown;
+ break;
+ default:
+ action = 0;
+ break;
+ }
+
+ if (action != 0) {
+ if (drawVerbose >= 2)
+ printf( "%s[%dx%d]\n", actionNames[action], bd->lastX, bd->lastY );
+ bd->action( bd, bd->context, action, bd->lastX, bd->lastY );
+ }
+
+ return TRUE;
+}
+
+
+
+static gint draw_leave_event(
+ GtkWidget *widget,
+ GdkEvent * event )
+{
+ gtkHelpHideBalloon();
+ return FALSE;
+}
+
+
+/**
+ * Handler for mouse button clicks.
+ */
+
+static gint draw_button_event(
+ GtkWidget *widget,
+ GdkEventButton *event,
+ wDraw_p bd )
+{
+ wAction_t action = 0;
+ if (bd->action == NULL)
+ return TRUE;
+
+ bd->lastX = OUTMAPX(bd, event->x);
+ bd->lastY = OUTMAPY(bd, event->y);
+
+ switch ( event->button ) {
+ case 1: /* left mouse button */
+ action = event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp;
+ /*bd->action( bd, bd->context, event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp, bd->lastX, bd->lastY );*/
+ break;
+ case 3: /* right mouse button */
+ action = event->type==GDK_BUTTON_PRESS?wActionRDown:wActionRUp;
+ /*bd->action( bd, bd->context, event->type==GDK_BUTTON_PRESS?wActionRDown:wActionRUp, bd->lastX, bd->lastY );*/
+ break;
+ }
+ if (action != 0) {
+ if (drawVerbose >= 2)
+ printf( "%s[%dx%d]\n", actionNames[action], bd->lastX, bd->lastY );
+ bd->action( bd, bd->context, action, bd->lastX, bd->lastY );
+ }
+ gtk_widget_grab_focus( bd->widget );
+ return TRUE;
+}
+
+static gint draw_motion_event(
+ GtkWidget *widget,
+ GdkEventMotion *event,
+ wDraw_p bd )
+{
+ int x, y;
+ GdkModifierType state;
+ wAction_t action;
+
+ if (bd->action == NULL)
+ return TRUE;
+
+ if (event->is_hint) {
+ gdk_window_get_pointer (event->window, &x, &y, &state);
+ } else {
+ x = event->x;
+ y = event->y;
+ state = event->state;
+ }
+
+ if (state & GDK_BUTTON1_MASK) {
+ action = wActionLDrag;
+ } else if (state & GDK_BUTTON3_MASK) {
+ action = wActionRDrag;
+ } else {
+ action = wActionMove;
+ }
+ bd->lastX = OUTMAPX(bd, x);
+ bd->lastY = OUTMAPY(bd, y);
+ if (drawVerbose >= 2)
+ printf( "%lx: %s[%dx%d] %s\n", (long)bd, actionNames[action], bd->lastX, bd->lastY, event->is_hint?"<Hint>":"<>" );
+ bd->action( bd, bd->context, action, bd->lastX, bd->lastY );
+ gtk_widget_grab_focus( bd->widget );
+ return TRUE;
+}
+
+
+static gint draw_char_event(
+ GtkWidget * widget,
+ GdkEventKey *event,
+ wDraw_p bd )
+{
+ guint key = event->keyval;
+ wAccelKey_e extKey = wAccelKey_None;
+ switch (key) {
+ case GDK_Escape: key = 0x1B; break;
+ case GDK_Return: key = 0x0D; break;
+ case GDK_Linefeed: key = 0x0A; break;
+ case GDK_Tab: key = 0x09; break;
+ case GDK_BackSpace: key = 0x08; break;
+ case GDK_Delete: extKey = wAccelKey_Del; break;
+ case GDK_Insert: extKey = wAccelKey_Ins; break;
+ case GDK_Home: extKey = wAccelKey_Home; break;
+ case GDK_End: extKey = wAccelKey_End; break;
+ case GDK_Page_Up: extKey = wAccelKey_Pgup; break;
+ case GDK_Page_Down: extKey = wAccelKey_Pgdn; break;
+ case GDK_Up: extKey = wAccelKey_Up; break;
+ case GDK_Down: extKey = wAccelKey_Down; break;
+ case GDK_Right: extKey = wAccelKey_Right; break;
+ case GDK_Left: extKey = wAccelKey_Left; break;
+ case GDK_F1: extKey = wAccelKey_F1; break;
+ case GDK_F2: extKey = wAccelKey_F2; break;
+ case GDK_F3: extKey = wAccelKey_F3; break;
+ case GDK_F4: extKey = wAccelKey_F4; break;
+ case GDK_F5: extKey = wAccelKey_F5; break;
+ case GDK_F6: extKey = wAccelKey_F6; break;
+ case GDK_F7: extKey = wAccelKey_F7; break;
+ case GDK_F8: extKey = wAccelKey_F8; break;
+ case GDK_F9: extKey = wAccelKey_F9; break;
+ case GDK_F10: extKey = wAccelKey_F10; break;
+ case GDK_F11: extKey = wAccelKey_F11; break;
+ case GDK_F12: extKey = wAccelKey_F12; break;
+ default: ;
+ }
+
+ if (extKey != wAccelKey_None) {
+ if ( gtkFindAccelKey( event ) == NULL ) {
+ bd->action( bd, bd->context, wActionExtKey + ((int)extKey<<8), bd->lastX, bd->lastY );
+ }
+ return TRUE;
+ } else if (key <= 0xFF && (event->state&(GDK_CONTROL_MASK|GDK_MOD1_MASK)) == 0 && bd->action) {
+ bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY );
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * Create
+ *
+*******************************************************************************/
+
+
+
+int XW = 0;
+int XH = 0;
+int xw, xh, cw, ch;
+
+EXPORT wDraw_p wDrawCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ long option,
+ wPos_t width,
+ wPos_t height,
+ void * context,
+ wDrawRedrawCallBack_p redraw,
+ wDrawActionCallBack_p action )
+{
+ wDraw_p bd;
+
+ bd = (wDraw_p)gtkAlloc( parent, B_DRAW, x, y, NULL, sizeof *bd, NULL );
+ bd->option = option;
+ bd->context = context;
+ bd->redraw = redraw;
+ bd->action = action;
+ gtkComputePos( (wControl_p)bd );
+
+ bd->widget = gtk_drawing_area_new();
+ gtk_drawing_area_size( GTK_DRAWING_AREA(bd->widget), width, height );
+ gtk_widget_set_size_request( GTK_WIDGET(bd->widget), width, height );
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "expose_event",
+ (GtkSignalFunc) draw_expose_event, bd);
+ gtk_signal_connect (GTK_OBJECT(bd->widget),"configure_event",
+ (GtkSignalFunc) draw_configure_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "motion_notify_event",
+ (GtkSignalFunc) draw_motion_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "button_press_event",
+ (GtkSignalFunc) draw_button_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "button_release_event",
+ (GtkSignalFunc) draw_button_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "scroll_event",
+ (GtkSignalFunc) draw_scroll_event, bd);
+ gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_press_event",
+ (GtkSignalFunc) draw_char_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "leave_notify_event",
+ (GtkSignalFunc) draw_leave_event, bd);
+ GTK_WIDGET_SET_FLAGS(GTK_WIDGET(bd->widget), GTK_CAN_FOCUS);
+ gtk_widget_set_events (bd->widget, GDK_EXPOSURE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+/* | GDK_SCROLL_MASK */
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK
+ | GDK_KEY_PRESS_MASK
+ | GDK_KEY_RELEASE_MASK );
+ bd->lastColor = -1;
+ bd->dpi = 75;
+ bd->maxW = bd->w = width;
+ bd->maxH = bd->h = height;
+
+ gtk_fixed_put( GTK_FIXED(parent->widget), bd->widget, bd->realX, bd->realY );
+ gtkControlGetSize( (wControl_p)bd );
+ gtk_widget_realize( bd->widget );
+ bd->pixmap = gdk_pixmap_new( bd->widget->window, width, height, -1 );
+ bd->gc = gdk_gc_new( parent->gtkwin->window );
+ gdk_gc_copy( bd->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+{
+ GdkCursor * cursor;
+ cursor = gdk_cursor_new ( GDK_TCROSS );
+ gdk_window_set_cursor ( bd->widget->window, cursor);
+ gdk_cursor_destroy (cursor);
+}
+#ifdef LATER
+ if (labelStr)
+ bd->labelW = gtkAddLabel( (wControl_p)bd, labelStr );
+#endif
+ gtk_widget_show( bd->widget );
+ gtkAddButton( (wControl_p)bd );
+ gtkAddHelpString( bd->widget, helpStr );
+
+ return bd;
+}
+
+/*******************************************************************************
+ *
+ * BitMaps
+ *
+*******************************************************************************/
+
+wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int arg )
+{
+ wDraw_p bd;
+
+ bd = (wDraw_p)gtkAlloc( gtkMainW, B_DRAW, 0, 0, NULL, sizeof *bd, NULL );
+
+ bd->lastColor = -1;
+ bd->dpi = 75;
+ bd->maxW = bd->w = w;
+ bd->maxH = bd->h = h;
+
+ bd->pixmap = gdk_pixmap_new( gtkMainW->widget->window, w, h, -1 );
+ if ( bd->pixmap == NULL ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: pixmap_new failed", "Ok", NULL );
+ return FALSE;
+ }
+ bd->gc = gdk_gc_new( gtkMainW->gtkwin->window );
+ if ( bd->gc == NULL ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: gc_new failed", "Ok", NULL );
+ return FALSE;
+ }
+ gdk_gc_copy( bd->gc, gtkMainW->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+
+ wDrawClear( bd );
+ return bd;
+}
+
+
+wBool_t wBitMapDelete( wDraw_p d )
+{
+ gdk_pixmap_unref( d->pixmap );
+ d->pixmap = NULL;
+ return TRUE;
+}
+
diff --git a/app/wlib/gtklib/gtkdraw.c b/app/wlib/gtklib/gtkdraw.c
new file mode 100644
index 0000000..b8f07ef
--- /dev/null
+++ b/app/wlib/gtklib/gtkdraw.c
@@ -0,0 +1,1044 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkdraw.c,v 1.9 2009-09-25 05:38:15 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "gtkint.h"
+#include "gdk/gdkkeysyms.h"
+
+static long drawVerbose = 0;
+
+struct wDrawBitMap_t {
+ int w;
+ int h;
+ int x;
+ int y;
+ const char * bits;
+ GdkPixmap * pixmap;
+ GdkBitmap * mask;
+ };
+
+struct wDraw_t {
+ WOBJ_COMMON
+ void * context;
+ wDrawActionCallBack_p action;
+ wDrawRedrawCallBack_p redraw;
+
+ GdkPixmap * pixmap;
+ GdkPixmap * pixmapBackup;
+
+ double dpi;
+
+ GdkGC * gc;
+ wDrawWidth lineWidth;
+ wDrawOpts opts;
+ wPos_t maxW;
+ wPos_t maxH;
+ unsigned long lastColor;
+ wBool_t lastColorInverted;
+ const char * helpStr;
+
+ wPos_t lastX;
+ wPos_t lastY;
+
+ wBool_t delayUpdate;
+ };
+
+struct wDraw_t psPrint_d;
+
+/*****************************************************************************
+ *
+ * MACROS
+ *
+ */
+
+#define LBORDER (22)
+#define RBORDER (6)
+#define TBORDER (6)
+#define BBORDER (20)
+
+#define INMAPX(D,X) (X)
+#define INMAPY(D,Y) (((D)->h-1) - (Y))
+#define OUTMAPX(D,X) (X)
+#define OUTMAPY(D,Y) (((D)->h-1) - (Y))
+
+
+/*******************************************************************************
+ *
+ * Basic Drawing Functions
+ *
+*******************************************************************************/
+
+
+
+static GdkGC * selectGC(
+ wDraw_p bd,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ if (width < 0.0) {
+ width = - width;
+ }
+/*
+ if ( color != bd->lastColor ) {
+ unsigned long pixColor;
+ unsigned long black, white;
+ white = WhitePixel(bd->display,DefaultScreen(bd->display));
+ black = BlackPixel(bd->display,DefaultScreen(bd->display));
+ pixColor = bd->colors[color] ^ white;
+ XSetForeground( bd->display, bd->normGc, pixColor );
+ bd->lastColor = color;
+ }
+*/
+ if (opts&wDrawOptTemp) {
+ if (bd->lastColor != color || !bd->lastColorInverted) {
+ gdk_gc_set_foreground( bd->gc, gtkGetColor(color,FALSE) );
+ bd->lastColor = color;
+ bd->lastColorInverted = TRUE;
+ }
+ gdk_gc_set_function( bd->gc, GDK_XOR );
+ gdk_gc_set_line_attributes( bd->gc, width,
+ GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ } else {
+ if (bd->lastColor != color || bd->lastColorInverted) {
+ gdk_gc_set_foreground( bd->gc, gtkGetColor(color,TRUE) );
+ bd->lastColor = color;
+ bd->lastColorInverted = FALSE;
+ }
+ gdk_gc_set_function( bd->gc, GDK_COPY );
+ if (lineType==wDrawLineDash) {
+ gdk_gc_set_line_attributes( bd->gc, width,
+ GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ /*XSetDashes( bd->display, bd->normGc, 0, "\003\003", 2 );*/
+ } else {
+ gdk_gc_set_line_attributes( bd->gc, width,
+ GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ }
+ return bd->gc;
+}
+
+
+EXPORT void wDrawDelayUpdate(
+ wDraw_p bd,
+ wBool_t delay )
+{
+ GdkRectangle update_rect;
+
+ if ( (!delay) && bd->delayUpdate ) {
+ update_rect.x = 0;
+ update_rect.y = 0;
+ update_rect.width = bd->w;
+ update_rect.height = bd->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+ }
+ bd->delayUpdate = delay;
+}
+
+
+EXPORT void wDrawLine(
+ wDraw_p bd,
+ wPos_t x0, wPos_t y0,
+ wPos_t x1, wPos_t y1,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintLine( x0, y0, x1, y1, width, lineType, color, opts );
+ return;
+ }
+ gc = selectGC( bd, width, lineType, color, opts );
+ x0 = INMAPX(bd,x0);
+ y0 = INMAPY(bd,y0);
+ x1 = INMAPX(bd,x1);
+ y1 = INMAPY(bd,y1);
+ gdk_draw_line( bd->pixmap, gc, x0, y0, x1, y1 );
+ if ( bd->delayUpdate || bd->widget == NULL ) return;
+ width /= 2;
+ if (x0 < x1) {
+ update_rect.x = x0-1-width;
+ update_rect.width = x1-x0+2+width+width;
+ } else {
+ update_rect.x = x1-1-width;
+ update_rect.width = x0-x1+2+width+width;
+ }
+ if (y0 < y1) {
+ update_rect.y = y0-1-width;
+ update_rect.height = y1-y0+2+width+width;
+ } else {
+ update_rect.y = y1-1-width;
+ update_rect.height = y0-y1+2+width+width;
+ }
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+EXPORT void wDrawArc(
+ wDraw_p bd,
+ wPos_t x0, wPos_t y0,
+ wPos_t r,
+ wAngle_t angle0,
+ wAngle_t angle1,
+ int drawCenter,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ int x, y, w, h;
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );
+ return;
+ }
+ gc = selectGC( bd, width, lineType, color, opts );
+ if (r < 6.0/75.0) return;
+ x = INMAPX(bd,x0-r);
+ y = INMAPY(bd,y0+r);
+ w = 2*r;
+ h = 2*r;
+ if (drawCenter)
+ gdk_draw_point( bd->pixmap, gc,
+ INMAPX(bd, x0 ), INMAPY(bd, y0 ) );
+ angle1 = -angle1;
+ angle0 = (-angle0) + 90.0;
+ gdk_draw_arc( bd->pixmap, gc, FALSE, x, y, w, h,
+ (int)(angle0*64.0), (int)(angle1*64.0) );
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ width /= 2;
+ update_rect.x = x-1-width;
+ update_rect.y = y-1-width;
+ update_rect.width = w+2+width+width;
+ update_rect.height = h+2+width+width;
+ gtk_widget_draw( bd->widget, &update_rect );
+
+}
+
+EXPORT void wDrawPoint(
+ wDraw_p bd,
+ wPos_t x0, wPos_t y0,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ /*psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );*/
+ return;
+ }
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opts );
+ gdk_draw_point( bd->pixmap, gc,
+ INMAPX(bd, x0 ), INMAPY(bd, y0 ) );
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = INMAPX(bd, x0 )-1;
+ update_rect.y = INMAPY(bd, y0 )-1;
+ update_rect.width = 2;
+ update_rect.height = 2;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+/*******************************************************************************
+ *
+ * Strings
+ *
+ ******************************************************************************/
+
+EXPORT void wDrawString(
+ wDraw_p bd,
+ wPos_t x, wPos_t y,
+ wAngle_t a,
+ const char * s,
+ wFont_p fp,
+ wFontSize_t fs,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ GdkGC * gc;
+ PangoLayout *layout;
+ GdkRectangle update_rect;
+ int w;
+ int h;
+ gint ascent;
+ gint descent;
+
+ if ( bd == &psPrint_d ) {
+ psPrintString( x, y, a, (char *)s, fp, fs, color, opts );
+ return;
+ }
+
+ x = INMAPX(bd,x);
+ y = INMAPY(bd,y);
+
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opts );
+
+ layout = gtkFontCreatePangoLayout(bd->widget, NULL, fp, fs, s,
+ (int *) &w, (int *) &h,
+ (int *) &ascent, (int *) &descent);
+
+ gdk_draw_layout(bd->pixmap, gc, x, y - ascent, layout);
+ gtkFontDestroyPangoLayout(layout);
+
+ if (bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = (gint) x - 1;
+ update_rect.y = (gint) y - ascent - 1;
+ update_rect.width = (gint) w + 2;
+ update_rect.height = (gint) ascent + (gint) descent + 2;
+ gtk_widget_draw(bd->widget, &update_rect);
+}
+
+EXPORT void wDrawGetTextSize(
+ wPos_t *w,
+ wPos_t *h,
+ wPos_t *d,
+ wDraw_p bd,
+ const char * s,
+ wFont_p fp,
+ wFontSize_t fs )
+{
+ int textWidth;
+ int textHeight;
+ int ascent;
+ int descent;
+
+ *w = 0;
+ *h = 0;
+
+ gtkFontDestroyPangoLayout(
+ gtkFontCreatePangoLayout(bd->widget, NULL, fp, fs, s,
+ &textWidth, (int *) &textHeight,
+ (int *) &ascent, (int *) &descent));
+
+ *w = (wPos_t) textWidth;
+ *h = (wPos_t) ascent;
+ *d = (wPos_t) descent;
+
+ if (debugWindow >= 3)
+ fprintf(stderr, "text metrics: w=%d, h=%d, d=%d\n", *w, *h, *d);
+}
+
+
+/*******************************************************************************
+ *
+ * Basic Drawing Functions
+ *
+*******************************************************************************/
+
+EXPORT void wDrawFilledRectangle(
+ wDraw_p bd,
+ wPos_t x,
+ wPos_t y,
+ wPos_t w,
+ wPos_t h,
+ wDrawColor color,
+ wDrawOpts opt )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintFillRectangle( x, y, w, h, color, opt );
+ return;
+ }
+
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
+ x = INMAPX(bd,x);
+ y = INMAPY(bd,y)-h;
+ gdk_draw_rectangle( bd->pixmap, gc, TRUE, x, y, w, h );
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = x-1;
+ update_rect.y = y-1;
+ update_rect.width = w+2;
+ update_rect.height = h+2;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+EXPORT void wDrawFilledPolygon(
+ wDraw_p bd,
+ wPos_t p[][2],
+ int cnt,
+ wDrawColor color,
+ wDrawOpts opt )
+{
+ GdkGC * gc;
+ static int maxCnt = 0;
+ static GdkPoint *points;
+ int i;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintFillPolygon( p, cnt, color, opt );
+ return;
+ }
+
+ if (cnt > maxCnt) {
+ if (points == NULL)
+ points = (GdkPoint*)malloc( cnt*sizeof *points );
+ else
+ points = (GdkPoint*)realloc( points, cnt*sizeof *points );
+ if (points == NULL)
+ abort();
+ maxCnt = cnt;
+ }
+
+ update_rect.x = bd->w;
+ update_rect.y = bd->h;
+ update_rect.width = 0;
+ update_rect.height = 0;
+ for (i=0; i<cnt; i++) {
+ points[i].x = INMAPX(bd,p[i][0]);
+ points[i].y = INMAPY(bd,p[i][1]);
+ if (update_rect.x > points[i].x)
+ update_rect.x = points[i].x;
+ if (update_rect.width < points[i].x)
+ update_rect.width = points[i].x;
+ if (update_rect.y > points[i].y)
+ update_rect.y = points[i].y;
+ if (update_rect.height < points[i].y)
+ update_rect.height = points[i].y;
+ }
+ update_rect.x -= 1;
+ update_rect.y -= 1;
+ update_rect.width -= update_rect.x-2;
+ update_rect.height -= update_rect.y-2;
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
+ gdk_draw_polygon( bd->pixmap, gc, TRUE,
+ points, cnt );
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+EXPORT void wDrawFilledCircle(
+ wDraw_p bd,
+ wPos_t x0,
+ wPos_t y0,
+ wPos_t r,
+ wDrawColor color,
+ wDrawOpts opt )
+{
+ GdkGC * gc;
+ int x, y, w, h;
+ GdkRectangle update_rect;
+
+ if ( bd == &psPrint_d ) {
+ psPrintFillCircle( x0, y0, r, color, opt );
+ return;
+ }
+
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opt );
+ x = INMAPX(bd,x0-r);
+ y = INMAPY(bd,y0+r);
+ w = 2*r;
+ h = 2*r;
+ gdk_draw_arc( bd->pixmap, gc, TRUE, x, y, w, h, 0, 360*64 );
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = x-1;
+ update_rect.y = y-1;
+ update_rect.width = w+2;
+ update_rect.height = h+2;
+ gtk_widget_draw( bd->widget, &update_rect );
+
+}
+
+
+EXPORT void wDrawClear(
+ wDraw_p bd )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+
+ gc = selectGC( bd, 0, wDrawLineSolid, wDrawColorWhite, 0 );
+ gdk_draw_rectangle(bd->pixmap, gc, TRUE, 0, 0,
+ bd->w, bd->h);
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+ update_rect.x = 0;
+ update_rect.y = 0;
+ update_rect.width = bd->w;
+ update_rect.height = bd->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+EXPORT void * wDrawGetContext(
+ wDraw_p bd )
+{
+ return bd->context;
+}
+
+/*******************************************************************************
+ *
+ * Bit Maps
+ *
+*******************************************************************************/
+
+
+EXPORT wDrawBitMap_p wDrawBitMapCreate(
+ wDraw_p bd,
+ int w,
+ int h,
+ int x,
+ int y,
+ const char * fbits )
+{
+ wDrawBitMap_p bm;
+
+ bm = (wDrawBitMap_p)malloc( sizeof *bm );
+ bm->w = w;
+ bm->h = h;
+ /*bm->pixmap = gtkMakeIcon( NULL, fbits, w, h, wDrawColorBlack, &bm->mask );*/
+ bm->bits = fbits;
+ bm->x = x;
+ bm->y = y;
+ return bm;
+}
+
+
+EXPORT void wDrawBitMap(
+ wDraw_p bd,
+ wDrawBitMap_p bm,
+ wPos_t x, wPos_t y,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ GdkGC * gc;
+ GdkRectangle update_rect;
+ int i, j, wb;
+ wPos_t xx, yy;
+ wControl_p b;
+ GdkDrawable * gdk_window;
+
+ x = INMAPX( bd, x-bm->x );
+ y = INMAPY( bd, y-bm->y )-bm->h;
+ wb = (bm->w+7)/8;
+ gc = selectGC( bd, 0, wDrawLineSolid, color, opts );
+ for ( i=0; i<bm->w; i++ )
+ for ( j=0; j<bm->h; j++ )
+ if ( bm->bits[ j*wb+(i>>3) ] & (1<<(i&07)) ) {
+ xx = x+i;
+ yy = y+j;
+ if ( 0 <= xx && xx < bd->w &&
+ 0 <= yy && yy < bd->h ) {
+ gdk_window = bd->pixmap;
+ b = (wControl_p)bd;
+ } else if ( (opts&wDrawOptNoClip) != 0 ) {
+ xx += bd->realX;
+ yy += bd->realY;
+ b = gtkGetControlFromPos( bd->parent, xx, yy );
+ if ( b ) {
+ if ( b->type == B_DRAW )
+ gdk_window = ((wDraw_p)b)->pixmap;
+ else
+ gdk_window = b->widget->window;
+ xx -= b->realX;
+ yy -= b->realY;
+ } else {
+ gdk_window = bd->parent->widget->window;
+ }
+ } else {
+ continue;
+ }
+/*printf( "gdk_draw_point( %ld, gc, %d, %d )\n", (long)gdk_window, xx, yy );*/
+ gdk_draw_point( gdk_window, gc, xx, yy );
+ if ( b && b->type == B_DRAW ) {
+ update_rect.x = xx-1;
+ update_rect.y = yy-1;
+ update_rect.width = 3;
+ update_rect.height = 3;
+ gtk_widget_draw( b->widget, &update_rect );
+ }
+ }
+#ifdef LATER
+ gdk_draw_pixmap(bd->pixmap, gc,
+ bm->pixmap,
+ 0, 0,
+ x, y,
+ bm->w, bm->h );
+#endif
+ if ( bd->delayUpdate || bd->widget == NULL) return;
+
+ update_rect.x = x;
+ update_rect.y = y;
+ update_rect.width = bm->w;
+ update_rect.height = bm->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+}
+
+
+/*******************************************************************************
+ *
+ * Event Handlers
+ *
+*******************************************************************************/
+
+
+
+EXPORT void wDrawSaveImage(
+ wDraw_p bd )
+{
+ if ( bd->pixmapBackup ) {
+ gdk_pixmap_unref( bd->pixmapBackup );
+ }
+ bd->pixmapBackup = gdk_pixmap_new( bd->widget->window, bd->w, bd->h, -1 );
+ selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 );
+ gdk_draw_pixmap( bd->pixmapBackup, bd->gc,
+ bd->pixmap,
+ 0, 0,
+ 0, 0,
+ bd->w, bd->h );
+}
+
+
+EXPORT void wDrawRestoreImage(
+ wDraw_p bd )
+{
+ GdkRectangle update_rect;
+ if ( bd->pixmapBackup ) {
+ selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 );
+ gdk_draw_pixmap( bd->pixmap, bd->gc,
+ bd->pixmapBackup,
+ 0, 0,
+ 0, 0,
+ bd->w, bd->h );
+ if ( bd->delayUpdate || bd->widget == NULL ) return;
+ update_rect.x = 0;
+ update_rect.y = 0;
+ update_rect.width = bd->w;
+ update_rect.height = bd->h;
+ gtk_widget_draw( bd->widget, &update_rect );
+ }
+}
+
+
+EXPORT void wDrawSetSize(
+ wDraw_p bd,
+ wPos_t w,
+ wPos_t h )
+{
+ wBool_t repaint;
+ if (bd == NULL) {
+ fprintf(stderr,"resizeDraw: no client data\n");
+ return;
+ }
+
+ /* Negative values crashes the program */
+ if (w < 0 || h < 0)
+ return;
+
+ repaint = (w != bd->w || h != bd->h);
+ bd->w = w;
+ bd->h = h;
+ gtk_widget_set_size_request( bd->widget, w, h );
+ if (repaint) {
+ if (bd->pixmap)
+ gdk_pixmap_unref( bd->pixmap );
+ bd->pixmap = gdk_pixmap_new( bd->widget->window, w, h, -1 );
+ wDrawClear( bd );
+ /*bd->redraw( bd, bd->context, w, h );*/
+ }
+ /*wRedraw( bd );*/
+}
+
+
+EXPORT void wDrawGetSize(
+ wDraw_p bd,
+ wPos_t *w,
+ wPos_t *h )
+{
+ if (bd->widget)
+ gtkControlGetSize( (wControl_p)bd );
+ *w = bd->w-2;
+ *h = bd->h-2;
+}
+
+
+EXPORT double wDrawGetDPI(
+ wDraw_p d )
+{
+ if (d == &psPrint_d)
+ return 1440.0;
+ else
+ return d->dpi;
+}
+
+
+EXPORT double wDrawGetMaxRadius(
+ wDraw_p d )
+{
+ if (d == &psPrint_d)
+ return 10e9;
+ else
+ return 32767.0;
+}
+
+
+EXPORT void wDrawClip(
+ wDraw_p d,
+ wPos_t x,
+ wPos_t y,
+ wPos_t w,
+ wPos_t h )
+{
+ GdkRectangle rect;
+ rect.width = w;
+ rect.height = h;
+ rect.x = INMAPX( d, x );
+ rect.y = INMAPY( d, y ) - rect.height;
+ gdk_gc_set_clip_rectangle( d->gc, &rect );
+
+}
+
+
+static gint draw_expose_event(
+ GtkWidget *widget,
+ GdkEventExpose *event,
+ wDraw_p bd)
+{
+ gdk_draw_pixmap(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ bd->pixmap,
+ event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ return FALSE;
+}
+
+
+static gint draw_configure_event(
+ GtkWidget *widget,
+ GdkEventConfigure *event,
+ wDraw_p bd)
+{
+ return FALSE;
+}
+
+static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown" };
+
+/**
+ * Handler for scroll events, ie mouse wheel activity
+ */
+
+static gint draw_scroll_event(
+ GtkWidget *widget,
+ GdkEventScroll *event,
+ wDraw_p bd)
+{
+ wAction_t action;
+
+ switch( event->direction ) {
+ case GDK_SCROLL_UP:
+ action = wActionWheelUp;
+ break;
+ case GDK_SCROLL_DOWN:
+ action = wActionWheelDown;
+ break;
+ default:
+ action = 0;
+ break;
+ }
+
+ if (action != 0) {
+ if (drawVerbose >= 2)
+ printf( "%s[%dx%d]\n", actionNames[action], bd->lastX, bd->lastY );
+ bd->action( bd, bd->context, action, bd->lastX, bd->lastY );
+ }
+
+ return TRUE;
+}
+
+
+
+static gint draw_leave_event(
+ GtkWidget *widget,
+ GdkEvent * event )
+{
+ gtkHelpHideBalloon();
+ return FALSE;
+}
+
+
+/**
+ * Handler for mouse button clicks.
+ */
+
+static gint draw_button_event(
+ GtkWidget *widget,
+ GdkEventButton *event,
+ wDraw_p bd )
+{
+ wAction_t action = 0;
+ if (bd->action == NULL)
+ return TRUE;
+
+ bd->lastX = OUTMAPX(bd, event->x);
+ bd->lastY = OUTMAPY(bd, event->y);
+
+ switch ( event->button ) {
+ case 1: /* left mouse button */
+ action = event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp;
+ /*bd->action( bd, bd->context, event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp, bd->lastX, bd->lastY );*/
+ break;
+ case 3: /* right mouse button */
+ action = event->type==GDK_BUTTON_PRESS?wActionRDown:wActionRUp;
+ /*bd->action( bd, bd->context, event->type==GDK_BUTTON_PRESS?wActionRDown:wActionRUp, bd->lastX, bd->lastY );*/
+ break;
+ }
+ if (action != 0) {
+ if (drawVerbose >= 2)
+ printf( "%s[%dx%d]\n", actionNames[action], bd->lastX, bd->lastY );
+ bd->action( bd, bd->context, action, bd->lastX, bd->lastY );
+ }
+ gtk_widget_grab_focus( bd->widget );
+ return TRUE;
+}
+
+static gint draw_motion_event(
+ GtkWidget *widget,
+ GdkEventMotion *event,
+ wDraw_p bd )
+{
+ int x, y;
+ GdkModifierType state;
+ wAction_t action;
+
+ if (bd->action == NULL)
+ return TRUE;
+
+ if (event->is_hint) {
+ gdk_window_get_pointer (event->window, &x, &y, &state);
+ } else {
+ x = event->x;
+ y = event->y;
+ state = event->state;
+ }
+
+ if (state & GDK_BUTTON1_MASK) {
+ action = wActionLDrag;
+ } else if (state & GDK_BUTTON3_MASK) {
+ action = wActionRDrag;
+ } else {
+ action = wActionMove;
+ }
+ bd->lastX = OUTMAPX(bd, x);
+ bd->lastY = OUTMAPY(bd, y);
+ if (drawVerbose >= 2)
+ printf( "%lx: %s[%dx%d] %s\n", (long)bd, actionNames[action], bd->lastX, bd->lastY, event->is_hint?"<Hint>":"<>" );
+ bd->action( bd, bd->context, action, bd->lastX, bd->lastY );
+ gtk_widget_grab_focus( bd->widget );
+ return TRUE;
+}
+
+
+static gint draw_char_event(
+ GtkWidget * widget,
+ GdkEventKey *event,
+ wDraw_p bd )
+{
+ guint key = event->keyval;
+ wAccelKey_e extKey = wAccelKey_None;
+ switch (key) {
+ case GDK_Escape: key = 0x1B; break;
+ case GDK_Return: key = 0x0D; break;
+ case GDK_Linefeed: key = 0x0A; break;
+ case GDK_Tab: key = 0x09; break;
+ case GDK_BackSpace: key = 0x08; break;
+ case GDK_Delete: extKey = wAccelKey_Del; break;
+ case GDK_Insert: extKey = wAccelKey_Ins; break;
+ case GDK_Home: extKey = wAccelKey_Home; break;
+ case GDK_End: extKey = wAccelKey_End; break;
+ case GDK_Page_Up: extKey = wAccelKey_Pgup; break;
+ case GDK_Page_Down: extKey = wAccelKey_Pgdn; break;
+ case GDK_Up: extKey = wAccelKey_Up; break;
+ case GDK_Down: extKey = wAccelKey_Down; break;
+ case GDK_Right: extKey = wAccelKey_Right; break;
+ case GDK_Left: extKey = wAccelKey_Left; break;
+ case GDK_F1: extKey = wAccelKey_F1; break;
+ case GDK_F2: extKey = wAccelKey_F2; break;
+ case GDK_F3: extKey = wAccelKey_F3; break;
+ case GDK_F4: extKey = wAccelKey_F4; break;
+ case GDK_F5: extKey = wAccelKey_F5; break;
+ case GDK_F6: extKey = wAccelKey_F6; break;
+ case GDK_F7: extKey = wAccelKey_F7; break;
+ case GDK_F8: extKey = wAccelKey_F8; break;
+ case GDK_F9: extKey = wAccelKey_F9; break;
+ case GDK_F10: extKey = wAccelKey_F10; break;
+ case GDK_F11: extKey = wAccelKey_F11; break;
+ case GDK_F12: extKey = wAccelKey_F12; break;
+ default: ;
+ }
+
+ if (extKey != wAccelKey_None) {
+ if ( gtkFindAccelKey( event ) == NULL ) {
+ bd->action( bd, bd->context, wActionExtKey + ((int)extKey<<8), bd->lastX, bd->lastY );
+ }
+ return TRUE;
+ } else if (key <= 0xFF && (event->state&(GDK_CONTROL_MASK|GDK_MOD1_MASK)) == 0 && bd->action) {
+ bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY );
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * Create
+ *
+*******************************************************************************/
+
+
+
+int XW = 0;
+int XH = 0;
+int xw, xh, cw, ch;
+
+EXPORT wDraw_p wDrawCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ long option,
+ wPos_t width,
+ wPos_t height,
+ void * context,
+ wDrawRedrawCallBack_p redraw,
+ wDrawActionCallBack_p action )
+{
+ wDraw_p bd;
+
+ bd = (wDraw_p)gtkAlloc( parent, B_DRAW, x, y, NULL, sizeof *bd, NULL );
+ bd->option = option;
+ bd->context = context;
+ bd->redraw = redraw;
+ bd->action = action;
+ gtkComputePos( (wControl_p)bd );
+
+ bd->widget = gtk_drawing_area_new();
+ gtk_drawing_area_size( GTK_DRAWING_AREA(bd->widget), width, height );
+ gtk_widget_set_size_request( GTK_WIDGET(bd->widget), width, height );
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "expose_event",
+ (GtkSignalFunc) draw_expose_event, bd);
+ gtk_signal_connect (GTK_OBJECT(bd->widget),"configure_event",
+ (GtkSignalFunc) draw_configure_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "motion_notify_event",
+ (GtkSignalFunc) draw_motion_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "button_press_event",
+ (GtkSignalFunc) draw_button_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "button_release_event",
+ (GtkSignalFunc) draw_button_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "scroll_event",
+ (GtkSignalFunc) draw_scroll_event, bd);
+ gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_press_event",
+ (GtkSignalFunc) draw_char_event, bd);
+ gtk_signal_connect (GTK_OBJECT (bd->widget), "leave_notify_event",
+ (GtkSignalFunc) draw_leave_event, bd);
+ GTK_WIDGET_SET_FLAGS(GTK_WIDGET(bd->widget), GTK_CAN_FOCUS);
+ gtk_widget_set_events (bd->widget, GDK_EXPOSURE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+/* | GDK_SCROLL_MASK */
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK
+ | GDK_KEY_PRESS_MASK
+ | GDK_KEY_RELEASE_MASK );
+ bd->lastColor = -1;
+ bd->dpi = 75;
+ bd->maxW = bd->w = width;
+ bd->maxH = bd->h = height;
+
+ gtk_fixed_put( GTK_FIXED(parent->widget), bd->widget, bd->realX, bd->realY );
+ gtkControlGetSize( (wControl_p)bd );
+ gtk_widget_realize( bd->widget );
+ bd->pixmap = gdk_pixmap_new( bd->widget->window, width, height, -1 );
+ bd->gc = gdk_gc_new( parent->gtkwin->window );
+ gdk_gc_copy( bd->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+{
+ GdkCursor * cursor;
+ cursor = gdk_cursor_new ( GDK_TCROSS );
+ gdk_window_set_cursor ( bd->widget->window, cursor);
+ gdk_cursor_destroy (cursor);
+}
+#ifdef LATER
+ if (labelStr)
+ bd->labelW = gtkAddLabel( (wControl_p)bd, labelStr );
+#endif
+ gtk_widget_show( bd->widget );
+ gtkAddButton( (wControl_p)bd );
+ gtkAddHelpString( bd->widget, helpStr );
+ return bd;
+}
+
+/*******************************************************************************
+ *
+ * BitMaps
+ *
+*******************************************************************************/
+
+wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int arg )
+{
+ wDraw_p bd;
+
+ bd = (wDraw_p)gtkAlloc( gtkMainW, B_DRAW, 0, 0, NULL, sizeof *bd, NULL );
+
+ bd->lastColor = -1;
+ bd->dpi = 75;
+ bd->maxW = bd->w = w;
+ bd->maxH = bd->h = h;
+
+ bd->pixmap = gdk_pixmap_new( gtkMainW->widget->window, w, h, -1 );
+ if ( bd->pixmap == NULL ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: pixmap_new failed", "Ok", NULL );
+ return FALSE;
+ }
+ bd->gc = gdk_gc_new( gtkMainW->gtkwin->window );
+ if ( bd->gc == NULL ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: gc_new failed", "Ok", NULL );
+ return FALSE;
+ }
+ gdk_gc_copy( bd->gc, gtkMainW->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+ wDrawClear( bd );
+ return bd;
+}
+
+
+wBool_t wBitMapDelete( wDraw_p d )
+{
+ gdk_pixmap_unref( d->pixmap );
+ d->pixmap = NULL;
+ return TRUE;
+}
diff --git a/app/wlib/gtklib/gtkfont.c b/app/wlib/gtklib/gtkfont.c
new file mode 100644
index 0000000..1a707f8
--- /dev/null
+++ b/app/wlib/gtklib/gtkfont.c
@@ -0,0 +1,320 @@
+/** \file gtkfont.c
+ * Font selection and loading.
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkfont.c,v 1.12 2009-12-07 19:31:31 m_fischer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "wlib.h"
+#include "gtkint.h"
+#include "i18n.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+/*
+ * Macro for debug purposes. Possible debug macro values:
+ *
+ * 0 - no messages to console (use this value when building in release mode)
+ * 1 - send errors
+ * 2 - send details
+ * 3 - send more details
+ */
+#define WLIB_FONT_DEBUG 0
+
+static gchar sampleText[] = "AbCdE0129!@$&()[]{}";
+
+static GtkWidget *fontSelectionDialog;
+
+
+/*****************************************************************************
+ * FONT HANDLERS
+ */
+
+#define FW_MEDIUM (0)
+#define FW_BOLD (1)
+#define FS_REGULAR (0)
+#define FS_ITALIC (1)
+
+/* absoluteFontSize was introduced to keep the font size information synchron
+ * between the Dt.size of ctext.c and it's drop list on the status bar and
+ * the font size coming from the gtk font dialog which is located in this file */
+int absoluteFontSize = 18;
+
+struct wFont_t {
+ PangoFontDescription *fontDescription;
+ };
+
+static wFont_p standardFonts[F_HELV-F_TIMES+1][2][2];
+static wFont_p curFont = NULL;
+
+
+static void fontSelectionDialogCallback(GtkFontSelectionDialog *fontSelectionDialog, gint response, gpointer data)
+{
+ gchar *fontName;
+
+ switch (response)
+ {
+ case GTK_RESPONSE_APPLY: /* once the apply button is hidden, this should not be used */
+ case GTK_RESPONSE_OK:
+ fontName = gtk_font_selection_dialog_get_font_name(fontSelectionDialog);
+ wPrefSetString( "font", "name", fontName );
+ pango_font_description_free(curFont->fontDescription);
+ curFont->fontDescription = pango_font_description_from_string(fontName);
+ absoluteFontSize = (pango_font_description_get_size(curFont->fontDescription))/PANGO_SCALE;
+#if WLIB_FONT_DEBUG >= 2
+ fprintf(stderr, "new font selection:\n");
+ fprintf(stderr, " font name \"%s\"\n", fontName);
+ fprintf(stderr, " font size is %d\n",pango_font_description_get_size(curFont->fontDescription)/PANGO_SCALE);
+ fprintf(stderr, " font size is absolute %d\n", pango_font_description_get_size_is_absolute(curFont->fontDescription));
+#endif
+ g_free(fontName);
+ break;
+ default:
+ gtk_widget_hide(GTK_WIDGET(fontSelectionDialog));
+ }
+ if (response == GTK_RESPONSE_OK)
+ gtk_widget_hide(GTK_WIDGET(fontSelectionDialog));
+}
+
+static wBool_t fontInitted = FALSE;
+
+static wBool_t fontInit()
+{
+ const char *fontNames[] = {
+ "times 18",
+ "times italic 18",
+ "times bold 18",
+ "times bold italic 18",
+ "helvetica 18",
+ "helvetica oblique 18",
+ "helvetica bold 18",
+ "helvetica bold oblique 18",
+ };
+
+ int s = 0;
+ int i, j, k;
+
+ for (i = F_TIMES; i <= F_HELV; ++i) {
+ for (j = FW_MEDIUM; j <= FW_BOLD; ++j) {
+ for (k = FS_REGULAR; k <= FS_ITALIC; ++k) {
+ PangoFontDescription *fontDescription = pango_font_description_from_string(fontNames[s++]);
+ wFont_p standardFont = (wFont_p) malloc(sizeof(struct wFont_t));
+ standardFont->fontDescription = fontDescription;
+ standardFonts[i-F_TIMES][j][k] = standardFont;
+ }
+ }
+ }
+
+ if (curFont == NULL) {
+ curFont = (wFont_p) malloc(sizeof(struct wFont_t));
+ if (curFont == NULL)
+ return FALSE;
+ const char *fontName = wPrefGetString("font", "name");
+ curFont->fontDescription = pango_font_description_from_string(fontName ? fontName : "helvetica 18");
+ absoluteFontSize = (int) PANGO_PIXELS(pango_font_description_get_size(curFont->fontDescription));
+ }
+
+ fontInitted = TRUE;
+ return TRUE;
+}
+
+
+static double fontFactor = 1.0;
+
+#define FONTSIZE_TO_PANGOSIZE(fs) ((gint) ((fs) * (fontFactor) + .5))
+
+PangoLayout *gtkFontCreatePangoLayout(GtkWidget *widget,
+ void *cairo,
+ wFont_p fp,
+ wFontSize_t fs,
+ const char *s,
+ int *width_p,
+ int *height_p,
+ int *ascent_p,
+ int *descent_p)
+{
+ if (!fontInitted)
+ fontInit();
+
+ PangoLayout *layout = NULL;
+
+ gchar *utf8 = gtkConvertInput(s);
+
+/* RPH -- pango_cairo_create_layout() is missing in CentOS 4.8.
+ CentOS 4.8 only has GTK 2.4.13 and Pango 1.6.0 and does not have
+ libpangocairo at all.
+ pango_cairo_create_layout() was introduced with Pango 1.10. */
+
+#if PANGO_VERSION_MAJOR >= 1 && PANGO_VERSION_MINOR >= 10
+ if (cairo != NULL) {
+ layout = pango_cairo_create_layout((cairo_t *) cairo);
+ pango_layout_set_text(layout, utf8, -1);
+ }
+ else
+#endif
+ layout = gtk_widget_create_pango_layout(widget, utf8);
+
+ PangoFontDescription *fontDescription = (fp ? fp : curFont)->fontDescription;
+
+ PangoContext *context;
+ PangoFontMetrics *metrics;
+
+ /* set attributes */
+ pango_font_description_set_size(fontDescription,
+ FONTSIZE_TO_PANGOSIZE(fs) * PANGO_SCALE);
+ pango_layout_set_font_description(layout, fontDescription);
+
+ /* get layout measures */
+ pango_layout_get_pixel_size(layout, width_p, height_p);
+ context = gtk_widget_get_pango_context(widget);
+ metrics = pango_context_get_metrics(context, fontDescription,
+ pango_context_get_language(context));
+ *ascent_p = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
+ *descent_p = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
+ pango_font_metrics_unref(metrics);
+
+#if WLIB_FONT_DEBUG >= 3
+ fprintf(stderr, "font layout created:\n");
+ fprintf(stderr, " widget: %p\n", widget);
+ //fprintf(stderr, " font description:%p\n", fp);
+ fprintf(stderr, " font size: %f\n", fs);
+ fprintf(stderr, " layout text: \"%s\" (utf8)\n", utf8);
+ fprintf(stderr, " layout width: %d\n", *width_p);
+ fprintf(stderr, " layout height: %d\n", *height_p);
+ fprintf(stderr, " layout ascent: %d (pixels)\n", *ascent_p);
+ fprintf(stderr, " layout descent: %d (pixels)\n", *descent_p);
+#endif
+
+ return layout;
+}
+
+void gtkFontDestroyPangoLayout(PangoLayout *layout)
+{
+ g_object_unref(G_OBJECT(layout));
+}
+
+void wInitializeFonts()
+{
+ if (!fontInitted)
+ fontInit();
+}
+
+void wSelectFont(
+ const char * title )
+{
+ if (!fontInitted)
+ fontInit();
+
+ if (fontSelectionDialog == NULL) {
+ fontSelectionDialog = gtk_font_selection_dialog_new(_("Font Select"));
+ gtk_window_set_position(GTK_WINDOW(fontSelectionDialog), GTK_WIN_POS_MOUSE);
+ gtk_window_set_modal(GTK_WINDOW(fontSelectionDialog), TRUE);
+ gtk_font_selection_dialog_set_preview_text(GTK_FONT_SELECTION_DIALOG(fontSelectionDialog), sampleText);
+ g_signal_connect(G_OBJECT(fontSelectionDialog), "response", G_CALLBACK(fontSelectionDialogCallback), NULL);
+ gtk_signal_connect(GTK_OBJECT(fontSelectionDialog), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &fontSelectionDialog);
+ }
+ gtk_window_set_title(GTK_WINDOW(fontSelectionDialog), title);
+
+ if (curFont != NULL) {
+ /* the curFont description contains the latest font info
+ * which is depended on the current scale
+ * overwrite it with the absoluteFontSize */
+ pango_font_description_set_size(curFont->fontDescription,FONTSIZE_TO_PANGOSIZE(absoluteFontSize) * PANGO_SCALE);
+ gchar *fontName = pango_font_description_to_string(curFont->fontDescription);
+ gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(fontSelectionDialog), fontName);
+ g_free(fontName);
+ }
+
+ gtk_widget_show(fontSelectionDialog);
+}
+
+static wFont_p gtkSelectedFont( void )
+{
+ if (!fontInitted)
+ fontInit();
+
+ return curFont;
+}
+
+wFontSize_t wSelectedFontSize( void )
+{
+ if (!fontInitted)
+ fontInit();
+
+#if WLIB_FONT_DEBUG >= 3
+ fprintf(stderr, "the font size of current font description is: %d\n",pango_font_description_get_size(curFont->fontDescription)/PANGO_SCALE);
+ fprintf(stderr, "the font size of absoluteFontSize is: %d\n",absoluteFontSize);
+#endif
+
+ //return (wFontSize_t) PANGO_PIXELS(pango_font_description_get_size(curFont->fontDescription));
+ return absoluteFontSize;
+}
+
+void wSetSelectedFontSize(int size){
+ absoluteFontSize = (wFontSize_t)size;
+}
+
+
+const char *gtkFontTranslate( wFont_p fp )
+{
+ static gchar *fontName = NULL;
+
+ if (fontName != NULL)
+ g_free(fontName);
+
+ if (!fontInitted)
+ fontInit();
+
+ if (fp == NULL)
+ fp = gtkSelectedFont();
+
+ if (fp == NULL)
+ fp = standardFonts[0][FW_MEDIUM][FS_REGULAR];
+
+ fontName = pango_font_description_to_string(fp->fontDescription);
+
+#if WLIB_FONT_DEBUG >= 2
+ fprintf(stderr, "font translation: ");
+ fprintf(stderr, " \"%s\"\n", fontName);
+#endif
+
+ return (const char *) fontName;
+}
+
+wFont_p wStandardFont( int face, wBool_t bold, wBool_t italic )
+{
+ if (!fontInitted)
+ fontInit();
+
+ return standardFonts[face-F_TIMES][bold][italic];
+}
diff --git a/app/wlib/gtklib/gtkhelp.c b/app/wlib/gtklib/gtkhelp.c
new file mode 100644
index 0000000..b02f555
--- /dev/null
+++ b/app/wlib/gtklib/gtkhelp.c
@@ -0,0 +1,733 @@
+/** \file gtkhelp.c
+ * Balloon help ( tooltips) and main help functions.
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkhelp.c,v 1.12 2009-10-02 04:30:32 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis and (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 <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdint.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include <webkit/webkit.h>
+
+#include "gtkint.h"
+#include "i18n.h"
+
+void load_into_view (char *file, int requested_view); // Prototype to please clang.
+
+/* globals and defines related to the HTML help window */
+
+#define HTMLERRORTEXT "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=US-ASCII\">" \
+ "<title>Help Error</title><body><h1>Error - help information can not be found.</h1><p>" \
+ "The help information you requested cannot be found on this system.<br><pre>%s: %s</pre><p>" \
+ "Usually this is an installation problem, Make sure that XTrackCAD and the included " \
+ "HTML files are installed properly and can be found via the XTRKCADLIB environment " \
+ "variable. Also make sure that the user has sufficient access rights to read these" \
+ "files.</p></body></html>"
+
+
+#define SLIDERPOSDEFAULT 180 /**< default value for slider position */
+
+#define HTMLHELPSECTION "gtklib html help" /**< section name for html help window preferences */
+#define SLIDERPREFNAME "sliderpos" /**< name for the slider position preference */
+#define WINDOWPOSPREFNAME "position" /**< name for the window position preference */
+#define WINDOWSIZEPREFNAME "size" /**< name for the window size preference */
+
+#define BACKBUTTON "back"
+#define FORWARDBUTTON "forward"
+#define HOMEBUTTON "home"
+#define CONTENTBUTTON "contents"
+#define TOCDOC "tocDoc"
+#define CONTENTSDOC "contentsDoc"
+#define TOCVIEW "viewLeft"
+#define CONTENTSVIEW "viewRight"
+#define PANED "hpane"
+
+enum pane_views { MAIN_VIEW, CONTENTS_VIEW };
+
+#define MAXHISTORYSIZE 20
+
+/** \struct htmlHistory
+ * for storing information about the browse history
+ */
+struct htmlHistory {
+ int curShownPage; /**< index of page that is shown currently */
+ int newestPage; /**< index of newest page loaded */
+ int oldestPage; /**< index of earliest page loaded */
+ int bInUse; /**< does buffer have at least one entry */
+ char *url[ MAXHISTORYSIZE ]; /**< array of pages in history */
+};
+
+static struct htmlHistory sHtmlHistory;
+
+#define INCBUFFERINDEX( x ) (((x) + 1 ) % MAXHISTORYSIZE )
+#define DECBUFFERINDEX( x ) ((x) == 0 ? MAXHISTORYSIZE - 1 : (x)-1)
+
+static char *directory; /**< base directory for HTML files */
+
+static GtkWidget *wHelpWindow; /**< handle for the help window */
+static GtkWidget *main_view; /** handle for the help main data pane */
+static GtkWidget *contents_view; /** handle for the help contents pane */
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+ g_object_set_data_full (G_OBJECT (component), name, \
+ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+ g_object_set_data (G_OBJECT (component), name, widget)
+
+static GtkWidget*
+lookup_widget(GtkWidget *widget, const gchar *widget_name)
+{
+ GtkWidget *parent, *found_widget;
+
+ for (;;)
+ {
+ if (GTK_IS_MENU (widget))
+ parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
+ else
+ parent = widget->parent;
+ if (!parent)
+ parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
+ if (parent == NULL)
+ break;
+ widget = parent;
+ }
+
+ found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
+ widget_name);
+ if (!found_widget)
+ g_warning ("Widget not found: %s", widget_name);
+ return found_widget;
+}
+
+
+
+/*
+ ******************************************************************************
+ *
+ * Help
+ *
+ ******************************************************************************
+ */
+
+wBool_t listHelpStrings = FALSE;
+wBool_t listMissingHelpStrings = FALSE;
+static char HelpDataKey[] = "HelpDataKey";
+
+static GtkWidget * balloonF;
+static GtkWidget * balloonPI;
+static wBalloonHelp_t * balloonHelpStrings;
+static int enableBalloonHelp = 1;
+static const char * balloonMsg;
+static wControl_p balloonB;
+static wPos_t balloonDx, balloonDy;
+static wBool_t balloonVisible = FALSE;
+static wControl_p balloonHelpB;
+static GtkTooltips * tooltips;
+
+
+void wSetBalloonHelp( wBalloonHelp_t * bh )
+{
+ balloonHelpStrings = bh;
+ if (!tooltips)
+ tooltips = gtk_tooltips_new();
+}
+
+void wEnableBalloonHelp( int enable )
+{
+ enableBalloonHelp = enable;
+ if (tooltips) {
+ if (enable)
+ gtk_tooltips_enable( tooltips );
+ else
+ gtk_tooltips_disable( tooltips );
+ }
+}
+
+
+void wControlSetBalloon( wControl_p b, wPos_t dx, wPos_t dy, const char * msg )
+{
+ PangoLayout * layout;
+ wPos_t x, y;
+ wPos_t w, h;
+ wPos_t xx, yy;
+ const char * msgConverted;
+ if (balloonVisible && balloonB == b &&
+ balloonDx == dx && balloonDy == dy && balloonMsg == msg )
+ return;
+
+ if ( msg == NULL ) {
+ if ( balloonF != NULL ) {
+ gtk_widget_hide( balloonF );
+ balloonVisible = FALSE;
+ }
+ balloonMsg = "";
+ return;
+ }
+ msgConverted = gtkConvertInput(msg);
+ if ( balloonF == NULL ) {
+ balloonF = gtk_window_new( GTK_WINDOW_POPUP );
+ gtk_window_set_policy( GTK_WINDOW (balloonF), FALSE, FALSE, TRUE );
+ gtk_widget_realize( balloonF );
+ balloonPI = gtk_label_new(msgConverted);
+ gtk_container_add( GTK_CONTAINER(balloonF), balloonPI );
+ gtk_container_border_width( GTK_CONTAINER(balloonF), 1 );
+ gtk_widget_show( balloonPI );
+ } else {
+ gtk_label_set( GTK_LABEL(balloonPI), msgConverted );
+ }
+ balloonDx = dx;
+ balloonDy = dy;
+ balloonB = b;
+ balloonMsg = msg;
+ gtk_widget_hide( balloonF );
+ layout = gtk_widget_create_pango_layout( balloonPI, msgConverted );
+ pango_layout_get_pixel_size( layout, &w, &h );
+ g_object_unref(G_OBJECT(layout));
+ h = 16;
+ gdk_window_get_position( GTK_WIDGET(b->parent->gtkwin)->window, &x, &y );
+ gdk_window_get_origin( GTK_WIDGET(b->parent->gtkwin)->window, &x, &y );
+ x += b->realX + dx;
+ y += b->realY + b->h - dy;
+ xx = gdk_screen_width();
+ yy = gdk_screen_height();
+ if ( x < 0 ) {
+ x = 0;
+ } else if ( x+w > xx ) {
+ x = xx - w;
+ }
+ if ( y < 0 ) {
+ y = 0;
+ } else if ( y+h > yy ) {
+ y = yy - h ;
+ }
+ gtk_widget_set_usize( balloonPI, w, h );
+ gtk_widget_set_usize( balloonF, w+2, h+2 );
+ gtk_widget_show( balloonF );
+ gtk_widget_set_uposition( balloonF, x, y );
+ /*gtk_widget_popup( balloonF, x, y );*/
+ gdk_draw_rectangle( balloonF->window, balloonF->style->fg_gc[GTK_STATE_NORMAL], FALSE, 0, 0, w+1, h+1 );
+ gtk_widget_queue_resize( GTK_WIDGET(balloonF) );
+ /*gtk_widget_set_uposition( balloonF, x, y );*/
+ balloonVisible = TRUE;
+}
+
+
+void wControlSetBalloonText(
+ wControl_p b,
+ const char * label )
+{
+ const char * helpStr;
+ if ( b->widget == NULL) abort();
+ helpStr = (char*)gtk_object_get_data( GTK_OBJECT(b->widget), HelpDataKey );
+ if ( helpStr == NULL ) helpStr = "NoHelp";
+ if (tooltips)
+ gtk_tooltips_set_tip( tooltips, b->widget, label, helpStr );
+}
+
+
+EXPORT void gtkHelpHideBalloon( void )
+{
+ if (balloonF != NULL && balloonVisible) {
+ gtk_widget_hide( balloonF );
+ balloonVisible = FALSE;
+ }
+}
+
+#ifdef XV_help
+static Notify_value showBalloonHelp( Notify_client client, int which )
+{
+ wControlSetBalloon( balloonHelpB, 0, 0, balloonHelpString );
+ return NOTIFY_DONE;
+}
+#endif
+
+static wWin_p balloonHelp_w;
+static wPos_t balloonHelp_x;
+static wPos_t balloonHelp_y;
+static void prepareBalloonHelp( wWin_p w, wPos_t x, wPos_t y )
+{
+#ifdef XV
+ wControl_p b;
+ char * hs;
+ int appNameLen = strlen( wAppName ) + 1;
+ if (w == NULL)
+ return;
+#ifdef LATER
+ if (!enableBalloonHelp)
+ return;
+#endif
+ if (!balloonHelpStrings)
+ return;
+
+ balloonHelp_w = w;
+ balloonHelp_x = x;
+ balloonHelp_y = y;
+
+ for ( b=w->first; b; b=b->next ) {
+ switch ( b->type ) {
+ case B_BUTTON:
+ case B_CANCEL:
+ case B_TEXT:
+ case B_INTEGER:
+ case B_LIST:
+ case B_DROPLIST:
+ case B_COMBOLIST:
+ case B_RADIO:
+ case B_TOGGLE:
+ case B_DRAW:
+ case B_MULTITEXT:
+ if (x >= b->realX && x < b->realX+b->w &&
+ y >= b->realY && y < b->realY+b->h ) {
+ hs = (char*)gtk_get( b->panel_item, XV_HELP_DATA );
+ if ( hs ) {
+ hs += appNameLen;
+ for ( currBalloonHelp = balloonHelpStrings; currBalloonHelp->name && strcmp(currBalloonHelp->name,hs) != 0; currBalloonHelp++ );
+ if (currBalloonHelp->name && balloonHelpB != b && currBalloonHelp->value ) {
+ balloonHelpB = b;
+ balloonHelpString = currBalloonHelp->value;
+ if (enableBalloonHelp) {
+ wControlSetBalloon( balloonHelpB, 0, 0, balloonHelpString );
+ /*setTimer( balloonHelpTimeOut, showBalloonHelp );*/
+ } else {
+ /*resetBalloonHelp();*/
+ }
+ }
+ return;
+ }
+ }
+ default:
+ ;
+ }
+ }
+ cancelTimer( showBalloonHelp );
+ resetBalloonHelp();
+#endif
+}
+
+
+void wBalloonHelpUpdate( void )
+{
+ balloonHelpB = NULL;
+ balloonMsg = NULL;
+ prepareBalloonHelp( balloonHelp_w, balloonHelp_x, balloonHelp_y );
+}
+
+
+void gtkAddHelpString(
+ GtkWidget * widget,
+ const char * helpStr )
+{
+ int rc;
+ char *string;
+ wBalloonHelp_t * bhp;
+ rc = 0;
+ if (helpStr==NULL || *helpStr==0)
+ return;
+ if ( balloonHelpStrings == NULL )
+ return;
+ for ( bhp = balloonHelpStrings; bhp->name && strcmp(bhp->name,helpStr) != 0; bhp++ );
+ if (listMissingHelpStrings && !bhp->name) {
+ printf( "Missing Help String: %s\n", helpStr );
+ return;
+ }
+ string = malloc( strlen(wAppName) + 5 + strlen(helpStr) + 1 );
+ sprintf( string, "%sHelp/%s", wAppName, helpStr );
+ if (tooltips)
+ gtk_tooltips_set_tip( tooltips, widget, _(bhp->value), string );
+ gtk_object_set_data( GTK_OBJECT( widget ), HelpDataKey, string );
+ if (listHelpStrings)
+ printf( "HELPSTR - %s\n", string );
+}
+
+
+EXPORT const char * wControlGetHelp(
+ wControl_p b ) /* Control */
+/*
+Returns the help topic string associated with <b>.
+*/
+{
+ const char * helpStr;
+ helpStr = (char*)gtk_object_get_data( GTK_OBJECT(b->widget), HelpDataKey );
+ return helpStr;
+}
+
+
+EXPORT void wControlSetHelp(
+ wControl_p b, /* Control */
+ const char * help ) /* topic string */
+/*
+Set the help topic string for <b> to <help>.
+*/
+{
+ const char * helpStr;
+ if (b->widget == 0) abort();
+ helpStr = wControlGetHelp(b);
+ if (tooltips)
+ gtk_tooltips_set_tip( tooltips, b->widget, help, helpStr );
+}
+
+
+/**
+ * create a new horizontal pane and place it into container.
+ * The separator position is read from the resource configuration and set accordingly.
+ * Also a callback is specified that will be executed when the slider has been moved.
+ *
+ * \PARAM container IN the container into which the pane will be stuffed.
+ * \PARAM property IN the name of the property for the slider position
+ *
+ * \return the HPaned handle
+ */
+
+GtkWidget *
+CreateHPaned( GtkBox *container, char *property )
+{
+ GtkWidget *hpaned;
+ long posSlider;
+
+ /* the horizontal slider */
+ hpaned = gtk_hpaned_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (hpaned), 6);
+
+ wPrefGetInteger( HTMLHELPSECTION, SLIDERPREFNAME, &posSlider, SLIDERPOSDEFAULT );
+ gtk_paned_set_position (GTK_PANED (hpaned), (int)posSlider);
+
+ /* pack the horizontal slider into the main window */
+ gtk_box_pack_start( container, hpaned, TRUE, TRUE, 0 );
+ gtk_widget_show( hpaned );
+
+ return( hpaned );
+}
+
+/**
+ * Handler for the delete-event issued on the help window.We are saving window
+ * information (eg. position) and are hiding the window instead of closing it.
+ *
+ * \PARAM win IN the window to be destroyed
+ * \PARAM event IN unused
+ * \PARAM ptr IN unused
+ *
+ * \RETURN FALSE
+ */
+
+static gboolean
+DestroyHelpWindow( GtkWidget *win, GdkEvent *event, void *ptr )
+{
+ int i;
+ GtkWidget *widget;
+ char tmp[ 20 ];
+
+ gint x, y;
+
+ /* get the slider position and save it */
+ widget = lookup_widget( win, PANED );
+ i = gtk_paned_get_position( GTK_PANED( widget ));
+ wPrefSetInteger( HTMLHELPSECTION, SLIDERPREFNAME, i );
+
+ /* get the window position */
+ gtk_window_get_position( (GtkWindow *)win, &x, &y );
+ sprintf( tmp, "%d %d", x, y );
+ wPrefSetString( HTMLHELPSECTION, WINDOWPOSPREFNAME, tmp );
+
+ /* get the window size */
+ gtk_window_get_size( (GtkWindow *)win , &x, &y );
+ sprintf( tmp, "%d %d", x, y );
+ wPrefSetString( HTMLHELPSECTION, WINDOWSIZEPREFNAME, tmp );
+
+ gtk_widget_hide( win );
+ return TRUE;
+}
+
+void back_button_clicked(GtkWidget *widget, gpointer data) {
+ webkit_web_view_go_back(WEBKIT_WEB_VIEW(data));
+}
+
+void forward_button_clicked(GtkWidget *widget, gpointer data) {
+ webkit_web_view_go_forward(WEBKIT_WEB_VIEW(data));
+}
+
+void home_button_clicked(GtkWidget *widget, gpointer data) {
+ load_into_view("index.html", MAIN_VIEW);
+}
+
+/* Toggles the contents pane */
+void contents_button_clicked(GtkWidget *widget, gpointer data) {
+ if (gtk_paned_get_position(GTK_PANED(data)) < 50) {
+ gtk_paned_set_position(GTK_PANED(data), 370);
+ }
+ else {
+ gtk_paned_set_position(GTK_PANED(data), 0);
+ }
+}
+
+gboolean contents_click_handler(
+ WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer data) {
+
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(data), webkit_network_request_get_uri(request));
+
+ return TRUE;
+}
+
+/**
+ * Initialize the buttons for the help window
+ */
+void initialize_buttons (GtkWidget *main_vbox, GtkWidget *content_hpane) {
+ GtkWidget *buttons_hbuttonbox;
+ GtkWidget *back_button;
+ GtkWidget *forward_button;
+ GtkWidget *home_button;
+ GtkWidget *contents_button;
+
+ // define and attach signals to buttons
+ back_button = gtk_button_new_with_label(_("Back"));
+ g_signal_connect(back_button, "clicked", G_CALLBACK(back_button_clicked), G_OBJECT(main_view));
+
+ forward_button = gtk_button_new_with_label(_("Forward"));
+ g_signal_connect(forward_button, "clicked", G_CALLBACK(forward_button_clicked), G_OBJECT(main_view));
+
+ home_button = gtk_button_new_with_label(_("Home"));
+ g_signal_connect(home_button, "clicked", G_CALLBACK(home_button_clicked), G_OBJECT(main_view));
+
+ contents_button = gtk_button_new_with_label(_("Contents"));
+ g_signal_connect(contents_button, "clicked", G_CALLBACK(contents_button_clicked), G_OBJECT(content_hpane));
+
+ // button layout
+ buttons_hbuttonbox = gtk_hbutton_box_new();
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), back_button);
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), forward_button);
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), home_button);
+ gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), contents_button);
+ gtk_box_pack_start(GTK_BOX(main_vbox), buttons_hbuttonbox, FALSE, TRUE, 0);
+ gtk_box_set_spacing(GTK_BOX(buttons_hbuttonbox), 6);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(buttons_hbuttonbox), GTK_BUTTONBOX_START);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT (main_view, back_button, BACKBUTTON);
+ GLADE_HOOKUP_OBJECT (main_view, forward_button, FORWARDBUTTON);
+ GLADE_HOOKUP_OBJECT (main_view, home_button, HOMEBUTTON);
+ GLADE_HOOKUP_OBJECT (main_view, contents_button, CONTENTBUTTON);
+}
+
+/**
+ * Create the help windows including all contained widgets and the needed HTML documents.
+ *
+ * \RETURN handle of the created window.
+ */
+
+GtkWidget*
+CreateHelpWindow (void)
+{
+ GtkWidget *main_vbox;
+ GtkWidget *main_view_scroller;
+ GtkWidget *contents_view_scroller;
+ GtkWidget *content_hpane;
+
+ int width;
+ int height;
+ int x, y;
+ int w = 0, h = 0;
+ const char *pref;
+ char title[100];
+
+ wHelpWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ width = gdk_screen_get_width( gtk_window_get_screen( (GtkWindow *)wHelpWindow ));
+ height = gdk_screen_get_height( gtk_window_get_screen( (GtkWindow *)wHelpWindow ));
+
+ pref = wPrefGetString( HTMLHELPSECTION, WINDOWSIZEPREFNAME );
+ if( pref ) {
+ sscanf( pref, "%d %d", &w, &h );
+ if( w > width )
+ w = width;
+ if( h > height )
+ h = height;
+ }
+ else {
+ w = ( width * 2 )/ 5;
+ h = height - 100;
+ }
+
+ pref = wPrefGetString( HTMLHELPSECTION, WINDOWPOSPREFNAME );
+ if( pref ) {
+ sscanf( pref, "%d %d", &x, &y );
+ if( y > height - h )
+ y = height - h;
+
+ if( x > width - w )
+ x = width - w;
+ }
+ else {
+ x = ( width * 3 ) / 5 - 10;
+ y = 70;
+ }
+
+ gtk_window_resize( (GtkWindow *)wHelpWindow, w, h );
+ gtk_window_move( (GtkWindow *)wHelpWindow, x, y );
+
+ gtk_window_set_title (GTK_WINDOW (wHelpWindow), "XTrkCad Help");
+
+ g_signal_connect( G_OBJECT( wHelpWindow ), "delete-event", G_CALLBACK( DestroyHelpWindow ), NULL );
+
+ main_view_scroller = gtk_scrolled_window_new(NULL, NULL);
+ contents_view_scroller = gtk_scrolled_window_new(NULL, NULL);
+ main_view = webkit_web_view_new();
+ contents_view = webkit_web_view_new();
+ // must be done here as it gets locked down later
+ load_into_view ("contents.html", CONTENTS_VIEW);
+ gtk_widget_set_size_request(GTK_WIDGET(wHelpWindow), x, y);
+
+ main_vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(wHelpWindow), main_vbox);
+
+ gtk_container_add(GTK_CONTAINER(main_view_scroller), main_view);
+
+ gtk_container_add(GTK_CONTAINER(contents_view_scroller), contents_view);
+
+ content_hpane = gtk_hpaned_new();
+ initialize_buttons(main_vbox, content_hpane);
+ gtk_container_add(GTK_CONTAINER(content_hpane), contents_view_scroller);
+ gtk_container_add(GTK_CONTAINER(content_hpane), main_view_scroller);
+ gtk_box_pack_start(GTK_BOX(main_vbox), content_hpane, TRUE, TRUE, 0);
+
+ gtk_paned_set_position(GTK_PANED(content_hpane), 370);
+
+ g_signal_connect(contents_view, "navigation-policy-decision-requested", G_CALLBACK(contents_click_handler), G_OBJECT(main_view));
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (wHelpWindow, wHelpWindow, "wHelpWindow");
+ GLADE_HOOKUP_OBJECT (wHelpWindow, content_hpane, PANED );
+ GLADE_HOOKUP_OBJECT (wHelpWindow, contents_view, TOCVIEW );
+ GLADE_HOOKUP_OBJECT (wHelpWindow, main_view, CONTENTSVIEW );
+
+ return wHelpWindow;
+}
+
+void load_into_view (char *file, int requested_view) {
+ GtkWidget *view;
+
+ switch (requested_view) {
+ case MAIN_VIEW:
+ view = main_view;
+ break;
+ case CONTENTS_VIEW:
+ view = contents_view;
+ break;
+ default:
+ printf("*** error, could not find view");
+ break;
+ }
+
+ char fileToLoad[100] = "file://";
+ strcat(fileToLoad,directory);
+ strcat(fileToLoad,file);
+
+ //debug printf("*** loading %s into pane %d.\n", fileToLoad, requested_view);
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(view), fileToLoad);
+}
+
+/**
+ * Invoke the help system to display help for <topic>.
+ *
+ * \param topic IN topic string
+ */
+
+EXPORT void wHelp( const char * topic )
+{
+ char *htmlFile;
+
+ if( !wHelpWindow )
+ {
+ directory = malloc( BUFSIZ );
+ assert( directory != NULL );
+
+ sprintf( directory, "%s/html/", wGetAppLibDir());
+
+ wHelpWindow = CreateHelpWindow();
+ /* load the default content */
+ load_into_view ("index.html", MAIN_VIEW);
+ }
+
+ /* need space for the 'html' extension plus dot plus \0 */
+ htmlFile = malloc( strlen( topic ) + 6 );
+ assert( htmlFile != NULL );
+
+ sprintf( htmlFile, "%s.html", topic );
+
+ load_into_view (htmlFile, MAIN_VIEW);
+ gtk_widget_show_all(wHelpWindow);
+ gtk_window_present(GTK_WINDOW(wHelpWindow));
+}
+
+/**
+ * Handle the commands issued from the Help drop-down. Currently, we only have a table
+ * of contents, but search etc. might be added in the future.
+ *
+ * \PARAM data IN command value
+ *
+ */
+
+static void
+DoHelpMenu( void *data )
+{
+ int func = (intptr_t)data;
+
+ switch( func )
+ {
+ case 1:
+ wHelp( "index" );
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+/**
+ * Add the entries for Help to the drop-down.
+ *
+ * \PARAM m IN handle of drop-down
+ *
+ */
+
+void wMenuAddHelp( wMenu_p m )
+{
+ wMenuPushCreate( m, NULL, _("&Contents"), 0, DoHelpMenu, (void*)1 );
+}
diff --git a/app/wlib/gtklib/gtkint.h b/app/wlib/gtklib/gtkint.h
new file mode 100644
index 0000000..4cbeace
--- /dev/null
+++ b/app/wlib/gtklib/gtkint.h
@@ -0,0 +1,180 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkint.h,v 1.8 2009-12-12 17:16:08 m_fischer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKINT_H
+#define GTKINT_H
+#include "wlib.h"
+
+#include "gdk/gdk.h"
+#include "gtk/gtk.h"
+
+#define EXPORT
+
+#ifdef WINDOWS
+#define strcasecmp _stricmp
+#endif
+
+#include "dynarr.h"
+
+extern wWin_p gtkMainW;
+
+typedef enum {
+ W_MAIN, W_POPUP,
+ B_BUTTON, B_CANCEL, B_POPUP, B_TEXT, B_INTEGER, B_FLOAT,
+ B_LIST, B_DROPLIST, B_COMBOLIST,
+ B_RADIO, B_TOGGLE,
+ B_DRAW, B_MENU, B_MULTITEXT, B_MESSAGE, B_LINES,
+ B_MENUITEM, B_BOX,
+ B_BITMAP } wType_e;
+
+typedef void (*repaintProcCallback_p)( wControl_p );
+typedef void (*doneProcCallback_p)( wControl_p b );
+typedef void (*setTriggerCallback_p)( wControl_p b );
+#define WOBJ_COMMON \
+ wType_e type; \
+ wControl_p next; \
+ wControl_p synonym; \
+ wWin_p parent; \
+ wPos_t origX, origY; \
+ wPos_t realX, realY; \
+ wPos_t labelW; \
+ wPos_t w, h; \
+ long option; \
+ const char * labelStr; \
+ repaintProcCallback_p repaintProc; \
+ GtkWidget * widget; \
+ GtkWidget * label; \
+ doneProcCallback_p doneProc; \
+ void * data;
+
+struct wWin_t {
+ WOBJ_COMMON
+ GtkWidget *gtkwin; /**< GTK window */
+ wPos_t lastX, lastY;
+ wControl_p first, last;
+ wWinCallBack_p winProc; /**< window procedure */
+ wBool_t shown; /**< visibility state */
+ const char * nameStr; /**< window name (not title) */
+ GtkWidget * menubar; /**< menubar handle (if exists) */
+ GdkGC * gc; /**< graphics context */
+ int gc_linewidth; /**< ??? */
+ wBool_t busy;
+ int modalLevel;
+ };
+
+struct wControl_t {
+ WOBJ_COMMON
+ };
+
+#define gtkIcon_bitmap (1)
+#define gtkIcon_pixmap (2)
+struct wIcon_t {
+ int gtkIconType;
+ wPos_t w;
+ wPos_t h;
+ wDrawColor color;
+ const void * bits;
+ };
+
+extern char wAppName[];
+extern char wConfigName[];
+extern wDrawColor wDrawColorWhite;
+extern wDrawColor wDrawColorBlack;
+
+/* gtkmisc.c */
+void * gtkAlloc( wWin_p, wType_e, wPos_t, wPos_t, const char *, int, void * );
+void gtkComputePos( wControl_p );
+void gtkAddButton( wControl_p );
+int gtkAddLabel( wControl_p, const char * );
+void gtkControlGetSize( wControl_p );
+struct accelData_t;
+struct accelData_t * gtkFindAccelKey( GdkEventKey * event );
+wBool_t gtkHandleAccelKey( GdkEventKey * );
+wBool_t catch_shift_ctrl_alt_keys( GtkWidget *, GdkEventKey *, void * );
+void gtkSetReadonly( wControl_p, wBool_t );
+wControl_p gtkGetControlFromPos( wWin_p, wPos_t, wPos_t );
+void gtkSetTrigger( wControl_p, setTriggerCallback_p );
+GdkPixmap * gtkMakeIcon( GtkWidget *, wIcon_p, GdkBitmap ** );
+char * gtkConvertInput( const char * );
+char * gtkConvertOutput( const char * );
+
+/* gtkwindow.c */
+void gtkDoModal( wWin_p, wBool_t );
+
+/* gtkhelp.c */
+void load_into_view( char *, int );
+void gtkAddHelpString( GtkWidget *, const char * );
+void gtkHelpHideBalloon( void );
+
+/* gtksimple.c */
+void gtkDrawBox( wWin_p, wBoxType_e, wPos_t, wPos_t, wPos_t, wPos_t );
+void gtkLineShow( wLine_p, wBool_t );
+
+/* gktlist.c */
+void gtkListShow( wList_p, wBool_t );
+void gtkListSetPos( wList_p );
+void gtkListActive( wList_p, wBool_t );
+void gtkDropListPos( wList_p );
+
+/* gtktext.c */
+void gtkTextFreeze( wText_p );
+void gtkTextThaw( wText_p );
+
+/* gtkfont.c */
+const char * gtkFontTranslate( wFont_p );
+PangoLayout *gtkFontCreatePangoLayout( GtkWidget *, void *cairo,
+ wFont_p, wFontSize_t, const char *,
+ int *, int *, int *, int * );
+
+/* gtkbutton.c */
+void gtkButtonDoAction( wButton_p );
+void gtkSetLabel( GtkWidget*, long, const char *, GtkLabel**, GtkWidget** );
+
+/* gtkcolor.c */
+void gtkGetColorMap( void );
+GdkColor * gtkGetColor( wDrawColor, wBool_t );
+int gtkGetColorChar( wDrawColor );
+void gtkPrintColorMap( FILE *, int, int );
+int gtkMapPixel( long );
+
+/* psprint.c */
+typedef struct {
+ wIndex_t cmdOrFile;
+ FILE * f;
+ } wPrinterStream_t;
+typedef wPrinterStream_t * wPrinterStream_p;
+
+wPrinterStream_p wPrinterOpen( void );
+void wPrinterWrite( wPrinterStream_p p, char * buff, int siz );
+void wPrinterClose( wPrinterStream_p );
+void psPrintLine( wPos_t, wPos_t, wPos_t, wPos_t,
+ wDrawWidth, wDrawLineType_e, wDrawColor, wDrawOpts );
+void psPrintArc( wPos_t, wPos_t, wPos_t, double, double, int,
+ wDrawWidth, wDrawLineType_e, wDrawColor, wDrawOpts );
+void psPrintString( wPos_t x, wPos_t y, double a, char * s,
+ wFont_p fp, double fs, wDrawColor color, wDrawOpts opts );
+
+void psPrintFillRectangle( wPos_t, wPos_t, wPos_t, wPos_t, wDrawColor, wDrawOpts );
+void psPrintFillPolygon( wPos_t [][2], int, wDrawColor, wDrawOpts );
+void psPrintFillCircle( wPos_t, wPos_t, wPos_t, wDrawColor, wDrawOpts );
+
+#endif
diff --git a/app/wlib/gtklib/gtklist.c b/app/wlib/gtklib/gtklist.c
new file mode 100644
index 0000000..b2c9799
--- /dev/null
+++ b/app/wlib/gtklib/gtklist.c
@@ -0,0 +1,1109 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtklist.c,v 1.4 2009-05-30 11:11:26 m_fischer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include "gtkint.h"
+#include "i18n.h"
+
+#define ROW_HEIGHT (15)
+#define PIX_TEXT_SEP (5)
+static char ListItemDataKey[] = "ListItemDataKey";
+
+/*
+ *****************************************************************************
+ *
+ * List Boxes
+ *
+ *****************************************************************************
+ */
+
+typedef struct wListItem_t * wListItem_p;
+
+struct wList_t {
+ WOBJ_COMMON
+ GtkWidget *list;
+ int count;
+ int number;
+ int colCnt;
+ wPos_t *colWidths;
+ wBool_t *colRightJust;
+ int last;
+ wPos_t listX;
+ long * valueP;
+ wListCallBack_p action;
+ int recursion;
+ int editted;
+ int editable;
+ };
+
+
+struct wListItem_t {
+ wBool_t active;
+ void * itemData;
+ const char * label;
+ GtkLabel * labelG;
+ wBool_t selected;
+ wList_p listP;
+ };
+
+
+static wListItem_p getListItem(
+ wList_p b,
+ wIndex_t inx,
+ GList ** childR )
+{
+ GList * child;
+ GtkObject * listItem;
+ wListItem_p id_p;
+ if (childR)
+ *childR = NULL;
+ if (b->list == 0) abort();
+ if (inx < 0)
+ return NULL;
+ if ( b->type == B_LIST )
+ return (wListItem_p)gtk_clist_get_row_data( GTK_CLIST(b->list), inx );
+
+ for ( child=GTK_LIST(b->list)->children; inx>0&&child; child=child->next,inx-- );
+ if (child==NULL) {
+ fprintf( stderr, "wListGetValues - End Of List\n" );
+ return NULL;
+ }
+ listItem = GTK_OBJECT(child->data);
+ id_p = (wListItem_p)gtk_object_get_data(listItem, ListItemDataKey );
+ if (id_p==NULL) {
+ fprintf( stderr, "wListGetValues - id_p == NULL\n" );
+ return NULL;
+ }
+ if (childR)
+ *childR = child;
+ return id_p;
+}
+
+
+EXPORT void wListClear(
+ wList_p b ) /* List */
+/*
+Remove all entries from the list <b>.
+*/
+{
+ if (b->list == 0) abort();
+ b->recursion++;
+ if ( b->type == B_DROPLIST )
+ gtk_list_clear_items( GTK_LIST(b->list), 0, b->count );
+ else
+ gtk_clist_clear( GTK_CLIST(b->list) );
+ b->recursion--;
+ b->last = -1;
+ b->count = 0;
+}
+
+
+EXPORT void wListSetIndex(
+ wList_p b, /* List */
+ int val ) /* Index */
+/*
+Makes the <val>th entry (0-origin) the current selection.
+If <val> if '-1' then no entry is selected.
+*/
+{
+ int cur;
+ wListItem_p id_p;
+
+ if (b->widget == 0) abort();
+ b->recursion++;
+ cur = b->last;
+ if ( b->type == B_DROPLIST ) {
+ if ((b->option&BL_NONE)!=0 && val < 0) {
+ if (cur != -1) {
+ gtk_list_unselect_item( GTK_LIST(b->list), cur );
+ }
+ } else {
+ if (cur != -1)
+ gtk_list_unselect_item( GTK_LIST(b->list), cur );
+ if (val != -1)
+ gtk_list_select_item( GTK_LIST(b->list), val );
+ }
+ } else {
+ if (cur != -1) {
+ gtk_clist_unselect_row( GTK_CLIST(b->list), cur, -1 );
+ id_p = getListItem( b, cur, NULL );
+ if ( id_p )
+ id_p->selected = FALSE;
+ }
+ if (val != -1) {
+ gtk_clist_select_row( GTK_CLIST(b->list), val, -1 );
+ id_p = getListItem( b, val, NULL );
+ if ( id_p )
+ id_p->selected = TRUE;
+ }
+ }
+ b->last = val;
+ b->recursion--;
+}
+
+
+static void parseLabelStr(
+ const char * labelStr,
+ int count,
+ char * * * texts )
+{
+ static char * labelBuffer;
+ static int labelBufferLen = 0;
+ static char * * textBuffer;
+ static int textBufferCount = 0;
+ char * cp;
+ int col;
+ int len;
+
+ labelStr = gtkConvertInput( labelStr );
+ len = strlen(labelStr)+1;
+ if ( len > labelBufferLen ) {
+ if ( labelBuffer )
+ labelBuffer = realloc( labelBuffer, len );
+ else
+ labelBuffer = (char*)malloc( len );
+ labelBufferLen = len;
+ }
+ if ( count > textBufferCount ) {
+ if ( textBuffer )
+ textBuffer = (char**)malloc( count * sizeof *textBuffer );
+ else
+ textBuffer = (char**)realloc( textBuffer, count * sizeof *textBuffer );
+ textBufferCount = count;
+ }
+
+ strcpy( labelBuffer, labelStr );
+ cp = labelBuffer;
+ for ( col=0; cp && col<count; col++ ) {
+ textBuffer[col] = cp;
+ cp = strchr( cp, '\t' );
+ if ( cp != NULL )
+ *cp++ = '\0';
+ }
+ for ( ; col<count; col++ )
+ textBuffer[col] = "";
+ *texts = textBuffer;
+}
+
+
+EXPORT void wListSetValue(
+ wList_p bl,
+ const char * val )
+{
+ if (bl->list==NULL) abort();
+ bl->recursion++;
+ if (bl->type == B_DROPLIST) {
+ bl->editted = TRUE;
+ gtk_entry_set_text( GTK_ENTRY(GTK_COMBO(bl->widget)->entry), val );
+ if (bl->action) {
+ bl->action( -1, val, 0, bl->data, NULL );
+ }
+ }
+ bl->recursion--;
+}
+
+
+EXPORT wIndex_t wListFindValue(
+ wList_p b,
+ const char * val )
+{
+ GList * child;
+ GtkObject * listItem;
+ wListItem_p id_p;
+ wIndex_t inx;
+
+ if (b->list==NULL) abort();
+ if (b->type == B_DROPLIST) {
+ for ( child=GTK_LIST(b->list)->children,inx=0; child; child=child->next,inx++ ) {
+ listItem = GTK_OBJECT(child->data);
+ id_p = (wListItem_p)gtk_object_get_data(listItem, ListItemDataKey );
+ if ( id_p && id_p->label && strcmp( id_p->label, val ) == 0 ) {
+ return inx;
+ }
+ }
+ } else {
+ for ( inx=0; inx<b->count; inx++ ) {
+ id_p = (wListItem_p)gtk_clist_get_row_data( GTK_CLIST(b->list), inx );
+ if ( id_p && id_p->label && strcmp( id_p->label, val ) == 0 )
+ return inx;
+ }
+ }
+ return -1;
+}
+
+EXPORT wIndex_t wListGetIndex(
+ wList_p b ) /* List */
+/*
+Returns the current selected list entry.
+If <val> if '-1' then no entry is selected.
+*/
+{
+ if (b->list == 0) abort();
+ return b->last;
+}
+
+EXPORT wIndex_t wListGetValues(
+ wList_p bl,
+ char * labelStr,
+ int labelSize,
+ void * * listDataRet,
+ void * * itemDataRet )
+
+{
+ wListItem_p id_p;
+ wIndex_t inx = bl->last;
+ const char * entry_value = "";
+ void * item_data = NULL;
+
+ if ( bl->list == 0 ) abort();
+ if ( bl->type == B_DROPLIST && bl->editted ) {
+ entry_value = gtk_entry_get_text( GTK_ENTRY(GTK_COMBO(bl->widget)->entry) );
+ inx = bl->last = -1;
+ } else {
+ inx = bl->last;
+ if (inx >= 0) {
+ id_p = getListItem( bl, inx, NULL );
+ if (id_p==NULL) {
+ fprintf( stderr, "wListGetValues - id_p == NULL\n" );
+ inx = -1;
+ } else {
+ entry_value = id_p->label;
+ item_data = id_p->itemData;
+ }
+ }
+ }
+ if ( labelStr ) {
+ strncpy( labelStr, entry_value, labelSize );
+ }
+ if ( listDataRet )
+ *listDataRet = bl->data;
+ if ( itemDataRet )
+ *itemDataRet = item_data;
+ return bl->last;
+}
+
+
+EXPORT wIndex_t wListGetCount(
+ wList_p b )
+{
+ return b->count;
+}
+
+
+EXPORT void * wListGetItemContext(
+ wList_p b,
+ wIndex_t inx )
+{
+ wListItem_p id_p;
+ if ( inx < 0 )
+ return NULL;
+ id_p = getListItem( b, inx, NULL );
+ if ( id_p )
+ return id_p->itemData;
+ else
+ return NULL;
+}
+
+
+EXPORT wBool_t wListGetItemSelected(
+ wList_p b,
+ wIndex_t inx )
+{
+ wListItem_p id_p;
+ if ( inx < 0 )
+ return FALSE;
+ id_p = getListItem( b, inx, NULL );
+ if ( id_p )
+ return id_p->selected;
+ else
+ return FALSE;
+}
+
+
+EXPORT wIndex_t wListGetSelectedCount(
+ wList_p b )
+{
+ wIndex_t selcnt, inx;
+ for ( selcnt=inx=0; inx<b->count; inx++ )
+ if ( wListGetItemSelected( b, inx ) )
+ selcnt++;
+ return selcnt;
+}
+
+
+EXPORT wBool_t wListSetValues(
+ wList_p b,
+ wIndex_t row,
+ const char * labelStr,
+ wIcon_p bm,
+ void *itemData )
+
+{
+ wListItem_p id_p;
+ GList * child;
+ GdkPixmap *pixmap;
+ GdkBitmap *bitmap = NULL;
+ char ** texts;
+ int col;
+
+ if (b->list == 0) abort();
+ b->recursion++;
+ id_p = getListItem( b, row, &child );
+ if (id_p != NULL) {
+ if ( b->type == B_DROPLIST ) {
+ gtk_label_set( id_p->labelG, labelStr?gtkConvertInput(labelStr):"" );
+ id_p->label = strdup( labelStr?labelStr:"" );
+ } else {
+ parseLabelStr( labelStr, b->colCnt, &texts );
+ for ( col=0; col<b->colCnt; col++ )
+ gtk_clist_set_text( GTK_CLIST(b->list), row, col, texts[col] );
+ if ( bm ) {
+ pixmap = gtkMakeIcon( b->widget, bm, &bitmap );
+ gtk_clist_set_pixtext( GTK_CLIST(b->list), row, 0, texts[0], 5, pixmap, bitmap );
+ gdk_pixmap_unref( pixmap );
+ gdk_bitmap_unref( bitmap );
+ }
+ }
+ id_p->itemData = itemData;
+ }
+ b->recursion--;
+ return TRUE;
+}
+
+
+EXPORT void wListDelete(
+ wList_p b,
+ wIndex_t inx )
+
+{
+ wListItem_p id_p;
+ GList * child;
+
+ if (b->list == 0) abort();
+ b->recursion++;
+ if ( b->type == B_DROPLIST ) {
+ id_p = getListItem( b, inx, &child );
+ if (id_p != NULL) {
+ gtk_container_remove( GTK_CONTAINER(b->list), child->data );
+ b->count--;
+ }
+ } else {
+ gtk_clist_remove( GTK_CLIST(b->list), inx );
+ b->count--;
+ }
+ b->recursion--;
+ return;
+}
+
+
+int wListGetColumnWidths(
+ wList_p bl,
+ int colCnt,
+ wPos_t * colWidths )
+{
+ int 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 gtkDropListAddValue(
+ wList_p b,
+ wListItem_p id_p )
+{
+ GtkWidget * listItem;
+
+ if ( id_p == NULL )
+ return;
+ id_p->labelG = (GtkLabel*)gtk_label_new( gtkConvertInput(id_p->label) );
+ /*gtk_misc_set_alignment( GTK_MISC(id_p->labelG), 0.0, 0.5 );*/
+ gtk_widget_show( GTK_WIDGET(id_p->labelG) );
+
+ listItem = gtk_list_item_new();
+ gtk_object_set_data( GTK_OBJECT(listItem), ListItemDataKey, id_p );
+ gtk_container_add( GTK_CONTAINER(listItem), GTK_WIDGET(id_p->labelG) );
+ gtk_misc_set_alignment( GTK_MISC(id_p->labelG), 0.0, 0.5 );
+ gtk_container_add( GTK_CONTAINER(b->list), listItem );
+ gtk_widget_show( listItem );
+}
+
+
+EXPORT wIndex_t wListAddValue(
+ wList_p b, /* List */
+ const char * labelStr, /* Entry name */
+ wIcon_p bm, /* Entry bitmap */
+ void * itemData ) /* User context */
+/*
+Adds a entry to the list <b> with name <name>.
+If list is created with 'BL_
+*/
+{
+ wListItem_p id_p;
+ GdkPixmap * pixmap = NULL;
+ GdkBitmap * bitmap;
+ static char ** texts;
+ GtkAdjustment *adj;
+
+ if (b->list == 0) abort();
+ b->recursion++;
+ id_p = (wListItem_p)malloc( sizeof *id_p );
+ memset( id_p, 0, sizeof *id_p );
+ id_p->itemData = itemData;
+ id_p->active = TRUE;
+ if ( labelStr == NULL )
+ labelStr = "";
+ id_p->label = strdup( labelStr );
+ id_p->listP = b;
+ if ( b->type == B_DROPLIST ) {
+ gtkDropListAddValue( b, id_p );
+ } else {
+ parseLabelStr( labelStr, b->colCnt, &texts );
+ gtk_clist_append( GTK_CLIST(b->list), texts );
+
+ /*
+ * this has taken forever to find out: the adjustment has to be notified
+ * about the list change by the program. So we need to get the current alignment.
+ * increment the upper value and then inform the scrolled window about the update.
+ * The upper value is increased only if the current value is smaller than the size
+ * of the list box.
+ */
+
+ adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(b->widget));
+
+ if( adj->upper < adj->step_increment * (b->count+1)) {
+ adj->upper += adj->step_increment;
+ gtk_adjustment_changed( adj );
+ }
+ if ( bm ) {
+ pixmap = gtkMakeIcon( b->widget, bm, &bitmap );
+ gtk_clist_set_pixtext( GTK_CLIST(b->list), b->count, 0, texts[0], 5, pixmap, bitmap );
+ gdk_pixmap_unref( pixmap );
+ gdk_bitmap_unref( bitmap );
+ }
+ gtk_clist_set_row_data( GTK_CLIST(b->list), b->count, id_p );
+ }
+
+ b->count++;
+ b->recursion--;
+ if ( b->count == 1 ) {
+ b->last = 0;
+ }
+ return b->count-1;
+}
+
+
+void wListSetSize( wList_p bl, wPos_t w, wPos_t h )
+{
+ /*gtk_widget_set_usize( bl->list, w, h );*/
+ if (bl->type == B_DROPLIST) {
+ /*gtk_widget_set_usize( GTK_COMBO(bl->widget)->entry, w, -1 );
+ gtk_widget_set_usize( GTK_COMBO(bl->widget)->list, w, -1 );*/
+#ifndef GTK1
+ gtk_widget_set_size_request( bl->widget, w, -1 );
+#else
+ gtk_widget_set_usize( bl->widget, w, -1 );
+#endif
+ } else {
+#ifndef GTK1
+ gtk_widget_set_size_request( bl->widget, w, h );
+#else
+ gtk_widget_set_usize( bl->widget, w, h );
+#endif
+ }
+ bl->w = w;
+ bl->h = h;
+}
+
+
+
+
+EXPORT void wListSetActive(
+ wList_p b, /* List */
+ int inx, /* Index */
+ wBool_t active ) /* Command */
+/*
+*/
+{
+ wListItem_p id_p;
+ GList * child;
+
+ if (b->list == 0) abort();
+ id_p = getListItem( b, inx, &child );
+ if (id_p == NULL)
+ return;
+ gtk_widget_set_sensitive( GTK_WIDGET(child->data), active );
+}
+
+
+EXPORT void wListSetEditable(
+ wList_p b,
+ wBool_t editable )
+{
+ b->editable = editable;
+ if ( b->type == B_DROPLIST )
+ gtk_widget_set_sensitive( GTK_WIDGET(GTK_COMBO(b->widget)->entry), b->editable );
+}
+
+
+static int selectCList(
+ GtkWidget * clist,
+ int row,
+ int col,
+ GdkEventButton* event,
+ gpointer data )
+{
+ wList_p bl = (wList_p)data;
+ wListItem_p id_p;
+
+ if (gdk_pointer_is_grabbed()) {
+ gdk_pointer_ungrab(0);
+ }
+ wFlush();
+ if (bl->recursion)
+ return 0;
+ id_p = gtk_clist_get_row_data( GTK_CLIST(clist), row );
+ if ( id_p == NULL ) return 1;
+ bl->editted = FALSE;
+ if ( (bl->option&BL_MANY)==0 && bl->last == row )
+ return 1;
+ bl->last = row;
+ id_p->selected = TRUE;
+ if (bl->valueP)
+ *bl->valueP = row;
+ if (bl->action)
+ bl->action( row, id_p->label, 1, bl->data, id_p->itemData );
+ return 1;
+}
+
+
+static int unselectCList(
+ GtkWidget * clist,
+ int row,
+ int col,
+ GdkEventButton* event,
+ gpointer data )
+{
+ wList_p bl = (wList_p)data;
+ wListItem_p id_p;
+
+ if (gdk_pointer_is_grabbed()) {
+ gdk_pointer_ungrab(0);
+ }
+ wFlush();
+ if (bl->recursion)
+ return 0;
+ id_p = gtk_clist_get_row_data( GTK_CLIST(clist), row );
+ if ( id_p == NULL ) return 1;
+ id_p->selected = FALSE;
+ if (bl->action)
+ bl->action( row, id_p->label, 2, bl->data, id_p->itemData );
+ return 1;
+}
+
+
+static int resizeColumnCList(
+ GtkWidget * clist,
+ int col,
+ int width,
+ gpointer data )
+{
+ wList_p bl = (wList_p)data;
+
+ if (gdk_pointer_is_grabbed()) {
+ gdk_pointer_ungrab(0);
+ }
+ wFlush();
+ if (bl->recursion)
+ return 0;
+ if ( col >= 0 && col < bl->colCnt )
+ bl->colWidths[col] = width;
+ return 0;
+}
+
+
+
+static int DropListSelectChild(
+ GtkWidget * list,
+ GtkWidget * listItem,
+ gpointer data )
+{
+ wList_p bl = (wList_p)data;
+ wListItem_p id_p=NULL;
+ wIndex_t inx;
+ GList * child;
+
+ if (gdk_pointer_is_grabbed()) {
+ gdk_pointer_ungrab(0);
+ }
+#ifdef LATER
+ printf( "DropListSelectChild %p %p %p\n", list, listItem, data );
+ printf( " b: recurs=%d widget=%p\n", bl->recursion, bl->list );
+#endif
+ if (bl->recursion)
+ return 0;
+ wFlush();
+ id_p = gtk_object_get_data(GTK_OBJECT(listItem), ListItemDataKey );
+ if ( id_p == NULL ) {
+ fprintf( stderr, " id_p = NULL\n");
+ return 0;
+ }
+#ifdef LATER
+ printf( " id_p = %s %lx, %d %d\n", id_p->label, (long)id_p->itemData, id_p->active, id_p->selected );
+#endif
+ if ( bl->type == B_DROPLIST && bl->editable ) {
+ if ( bl->editted == FALSE )
+ return 0;
+ gtkSetTrigger( NULL, NULL );
+ }
+ bl->editted = FALSE;
+ for ( inx=0,child=GTK_LIST(bl->list)->children,inx=0; child&&child->data!=listItem; child=child->next ) inx++;
+ if ( bl->last == inx )
+ return 1;
+ bl->last = inx;
+ if (bl->valueP)
+ *bl->valueP = inx;
+ if (id_p && bl->action)
+ bl->action( (wIndex_t)inx, id_p->label, 1, bl->data, id_p->itemData );
+ gtkSetTrigger( NULL, NULL );
+ return 1;
+}
+
+
+#ifdef LATER
+static int DropListSelectionChanged(
+ GtkWidget * list,
+ gpointer data )
+{
+ wList_p bl = (wList_p)data;
+ wListItem_p id_p=NULL;
+ GList * child;
+ GList * dlist;
+ wIndex_t inx;
+ GtkObject * listItem;
+ if (gdk_pointer_is_grabbed()) {
+ gdk_pointer_ungrab(0);
+ }
+ if (bl->recursion)
+ return 0;
+ wFlush();
+ if ( bl->type == B_DROPLIST && bl->editable ) {
+ if ( bl->editted == FALSE )
+ return 0;
+ gtkSetTrigger( NULL, NULL );
+ }
+
+ dlist = GTK_LIST(bl->list)->selection;
+ if (dlist == NULL) {
+ return 0;
+ }
+ inx = 0;
+ for ( child=GTK_LIST(bl->list)->children,inx=0; child&&child->data!=dlist->data; child=child->next ) inx++;
+ while (dlist) {
+ listItem = GTK_OBJECT(dlist->data);
+ id_p = gtk_object_get_data(listItem, ListItemDataKey );
+ printf( "DropListSelectionChanged: id_p = %s %lx\n", id_p->label, (long)id_p->itemData );
+ dlist = dlist->next;
+ }
+ return 0;
+#ifdef LATER
+ bl->editted = FALSE;
+ if ( bl->last == inx )
+ return 1;
+ bl->last = inx;
+ if (bl->valueP)
+ *bl->valueP = inx;
+ if (id_p && bl->action)
+ bl->action( inx, id_p->label, 1, bl->data, id_p->itemData );
+ gtkSetTrigger( NULL, NULL );
+ return 1;
+#endif
+}
+
+#endif
+
+
+static void triggerDListEntry(
+ wControl_p b )
+{
+ wList_p bl = (wList_p)b;
+ const char * entry_value;
+
+ if (bl == 0)
+ return;
+ if (bl->widget == 0) abort();
+ entry_value = gtk_entry_get_text( GTK_ENTRY(GTK_COMBO(bl->widget)->entry) );
+ if (entry_value == NULL) return;
+ if (debugWindow >= 2) printf("triggerListEntry: %s text = %s\n", bl->labelStr?bl->labelStr:"No label", entry_value );
+ if (bl->action) {
+ bl->recursion++;
+ bl->action( -1, entry_value, 0, bl->data, NULL );
+ bl->recursion--;
+ }
+ gtkSetTrigger( NULL, NULL );
+ return;
+}
+
+
+static void updateDListEntry(
+ GtkEntry * widget,
+ wList_p bl )
+{
+ const char *entry_value;
+ if (bl == 0)
+ return;
+ if (bl->recursion)
+ return;
+ if (!bl->editable)
+ return;
+ entry_value = gtk_entry_get_text( GTK_ENTRY(GTK_COMBO(bl->widget)->entry) );
+ bl->editted = TRUE;
+ if (bl->valueP != NULL)
+ *bl->valueP = -1;
+ bl->last = -1;
+ if (bl->action)
+ gtkSetTrigger( (wControl_p)bl, triggerDListEntry );
+ return;
+}
+
+
+
+#ifdef LATER
+EXPORT wList_p wListCreate(
+ wWin_p parent, /* Parent window */
+ wPos_t x, /* X-position */
+ wPos_t y, /* Y-position */
+ const char * helpStr, /* Help string */
+ const char * labelStr, /* Label */
+ long option, /* Options */
+ long number, /* Number of displayed entries */
+ wPos_t width, /* Width of list */
+ long *valueP, /* Selected index */
+ wListCallBack_p action, /* Callback */
+ void *data ) /* Context */
+/*
+*/
+{
+ wList_p b;
+
+ b = (wList_p)gtkAlloc( parent, B_LIST, x, y, labelStr, sizeof *b, data );
+ b->option = option;
+ b->number = number;
+ b->count = 0;
+ b->last = -1;
+ b->valueP = valueP;
+ b->action = action;
+ b->listX = b->realX;
+ b->colCnt = 0;
+ b->colWidths = NULL;
+ b->colRightJust = NULL;
+ gtkComputePos( (wControl_p)b );
+
+ b->list = (GtkWidget*)gtk_clist_new(1);
+ if (b->list == 0) abort();
+ b->widget = gtk_scrolled_window_new( NULL, NULL );
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (b->widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+ /*gtk_container_add( GTK_CONTAINER(b->widget), b->list );*/
+ gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(b->widget), b->list );
+ if (width == 0)
+ width = 100;
+ gtk_clist_set_column_width( GTK_CLIST(b->list), 0, width );
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, width, (number+1)*ROW_HEIGHT );
+#else
+ gtk_widget_set_usize( b->widget, width, (number+1)*ROW_HEIGHT );
+#endif
+ gtk_signal_connect( GTK_OBJECT(b->list), "select_row", GTK_SIGNAL_FUNC(selectCList), b );
+ gtk_signal_connect( GTK_OBJECT(b->list), "unselect_row", GTK_SIGNAL_FUNC(unselectCList), b );
+ gtk_list_set_selection_mode( GTK_LIST(b->list), (option&BL_MANY)?GTK_SELECTION_MULTIPLE:GTK_SELECTION_BROWSE );
+/* gtk_container_set_focus_vadjustment (GTK_CONTAINER (b->list),
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (b->widget))); */
+ gtk_widget_show( b->list );
+
+#ifndef GTK1
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), b->widget );
+ gtk_widget_set_uposition( b->widget, b->realX, b->realY );
+#endif
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ gtkAddHelpString( b->widget, helpStr );
+ return b;
+}
+#endif
+
+/** Create a drop down list. The drop down is created and intialized with the supplied values.
+ *
+ * \param IN parent Parent window
+ * \param IN x, X-position
+ * \param IN y Y-position
+ * \param IN helpStr Help string
+ * \param IN labelStr Label
+ * \param IN option Options
+ * \param IN number Number of displayed entries
+ * \param IN width Width
+ * \param IN valueP Selected index
+ * \param IN action Callback
+ * \param IN data Context
+ */
+
+EXPORT wList_p wDropListCreate(
+ wWin_p parent, /* Parent window */
+ wPos_t x, /* X-position */
+ wPos_t y, /* Y-position */
+ const char * helpStr, /* Help string */
+ const char * labelStr, /* Label */
+ long option, /* Options */
+ long number, /* Number of displayed entries */
+ wPos_t width, /* Width */
+ long *valueP, /* Selected index */
+ wListCallBack_p action, /* Callback */
+ void *data ) /* Context */
+/*
+*/
+{
+ wList_p b;
+ b = (wList_p)gtkAlloc( parent, B_DROPLIST, x, y, labelStr, sizeof *b, data );
+ b->option = option;
+ b->number = number;
+ b->count = 0;
+ b->last = -1;
+ b->valueP = valueP;
+ b->action = action;
+ b->listX = b->realX;
+ b->colCnt = 0;
+ b->colWidths = NULL;
+ b->colRightJust = NULL;
+ gtkComputePos( (wControl_p)b );
+
+ b->widget = (GtkWidget*)gtk_combo_new();
+ if (b->widget == 0) abort();
+ b->list = GTK_COMBO(b->widget)->list;
+#ifdef LATER
+ gtk_signal_connect( GTK_OBJECT(b->list), "selection_changed", GTK_SIGNAL_FUNC(DropListSelectionChanged), b );
+#endif
+ gtk_signal_connect( GTK_OBJECT(b->list), "select_child", GTK_SIGNAL_FUNC(DropListSelectChild), b );
+ if (width == 0)
+ width = 100;
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, width, -1 );
+ gtk_widget_set_size_request( GTK_COMBO(b->widget)->entry, width, -1 );
+#else
+ gtk_widget_set_usize( b->widget, width, -1 );
+ gtk_widget_set_usize( GTK_COMBO(b->widget)->entry, width, -1 );
+#endif
+
+ gtk_signal_connect( GTK_OBJECT(GTK_COMBO(b->widget)->entry), "changed", GTK_SIGNAL_FUNC(updateDListEntry), b );
+ if ( (option&BL_EDITABLE) == 0 )
+ gtk_widget_set_sensitive( GTK_WIDGET(GTK_COMBO(b->widget)->entry), FALSE );
+ else {
+ b->editable = TRUE;
+ }
+
+#ifndef GTK1
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), b->widget );
+ gtk_widget_set_uposition( b->widget, b->realX, b->realY );
+#endif
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ gtkAddHelpString( b->widget, helpStr );
+ return b;
+
+}
+
+
+EXPORT wList_p wComboListCreate(
+ wWin_p parent, /* Parent window */
+ wPos_t x, /* X-position */
+ wPos_t y, /* Y-position */
+ const char * helpStr, /* Help string */
+ const char * labelStr, /* Label */
+ long option, /* Options */
+ long number, /* Number of displayed list entries */
+ wPos_t width, /* Width */
+ long *valueP, /* Selected index */
+ wListCallBack_p action, /* Callback */
+ void *data ) /* Context */
+/*
+*/
+{
+ return wListCreate( parent, x, y, helpStr, labelStr, option, number, width, 0, NULL, NULL, NULL, valueP, action, data );
+#ifdef LATER
+ wList_p b;
+
+ b = (wList_p)gtkAlloc( parent, B_LIST, x, y, labelStr, sizeof *b, data );
+ b->option = option;
+ b->number = number;
+ b->count = 0;
+ b->last = -1;
+ b->valueP = valueP;
+ b->action = action;
+ b->listX = b->realX;
+ gtkComputePos( (wControl_p)b );
+
+ b->widget = (GtkWidget*)gtk_combo_new();
+ if (b->widget == 0) abort();
+ if (width == 0)
+ width = 100;
+ /*gtk_clist_set_column_width( GTK_CLIST(b->widget), 0, width );*/
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, width, -1 );
+#else
+ gtk_widget_set_usize( b->widget, width, -1 );
+#endif
+
+#ifndef GTK1
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), b->widget );
+ gtk_widget_set_uposition( b->widget, b->realX, b->realY );
+#endif
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ gtkAddHelpString( b->widget, helpStr );
+ return b;
+#endif
+}
+
+
+
+EXPORT wList_p wListCreate(
+ wWin_p parent, /* Parent window */
+ wPos_t x, /* X-position */
+ wPos_t y, /* Y-position */
+ const char * helpStr, /* Help string */
+ const char * labelStr, /* Label */
+ long option, /* Options */
+ long number, /* Number of displayed entries */
+ wPos_t width, /* Width of list */
+ int colCnt, /* Number of columns */
+ wPos_t * colWidths, /* Width of columns */
+ wBool_t * colRightJust, /* justification of columns */
+ const char ** colTitles, /* Title of columns */
+ long *valueP, /* Selected index */
+ wListCallBack_p action, /* Callback */
+ void *data ) /* Context */
+/*
+*/
+{
+ wList_p bl;
+ long col;
+ static wPos_t zeroPos = 0;
+
+ bl = (wList_p)gtkAlloc( parent, B_LIST, x, y, labelStr, sizeof *bl, data );
+ bl->option = option;
+ bl->number = number;
+ bl->count = 0;
+ bl->last = -1;
+ bl->valueP = valueP;
+ bl->action = action;
+ bl->listX = bl->realX;
+
+ if ( colCnt <= 0 ) {
+ colCnt = 1;
+ colWidths = &zeroPos;
+ }
+ bl->colCnt = colCnt;
+ bl->colWidths = (wPos_t*)malloc( colCnt * sizeof *(wPos_t*)0 );
+ memcpy( bl->colWidths, colWidths, colCnt * sizeof *(wPos_t*)0 );
+
+ gtkComputePos( (wControl_p)bl );
+
+ bl->list = (GtkWidget*)gtk_clist_new( bl->colCnt );
+ if (bl->list == 0) abort();
+ if (colTitles)
+ {
+ for (col = 0; col < colCnt; col++)
+ gtk_clist_set_column_title(GTK_CLIST(bl->list), col, _(((char*)colTitles[col])));
+ gtk_clist_column_titles_show(GTK_CLIST(bl->list));
+ }
+
+ bl->widget = gtk_scrolled_window_new( NULL, NULL );
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (bl->widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+ /* gtk_container_add( GTK_CONTAINER(bl->widget), bl->list ); */
+ gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(bl->widget), bl->list );
+ if (width == 0)
+ width = 100;
+ for ( col=0; col<colCnt; col++ ) {
+ gtk_clist_set_column_auto_resize( GTK_CLIST(bl->list), col, TRUE );
+ gtk_clist_set_column_resizeable( GTK_CLIST(bl->list), col, TRUE );
+ gtk_clist_set_column_justification( GTK_CLIST(bl->list), col,
+ (colRightJust==NULL||colRightJust[col]==FALSE)?GTK_JUSTIFY_LEFT:GTK_JUSTIFY_RIGHT );
+ gtk_clist_set_column_width( GTK_CLIST(bl->list), col, bl->colWidths[col] );
+ }
+#ifndef GTK1
+ gtk_widget_set_size_request( bl->widget, width, (number+1)*ROW_HEIGHT );
+#else
+ gtk_widget_set_usize( bl->widget, width, (number+1)*ROW_HEIGHT );
+#endif
+ gtk_signal_connect( GTK_OBJECT(bl->list), "select_row", GTK_SIGNAL_FUNC(selectCList), bl );
+ gtk_signal_connect( GTK_OBJECT(bl->list), "unselect_row", GTK_SIGNAL_FUNC(unselectCList), bl );
+ gtk_signal_connect( GTK_OBJECT(bl->list), "resize_column", GTK_SIGNAL_FUNC(resizeColumnCList), bl );
+ gtk_clist_set_selection_mode( GTK_CLIST(bl->list), (option&BL_MANY)?GTK_SELECTION_MULTIPLE:GTK_SELECTION_BROWSE );
+ gtk_container_set_focus_vadjustment (GTK_CONTAINER (bl->list),
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (bl->widget)));
+
+ gtk_widget_show( bl->list );
+
+#ifndef GTK1
+ gtk_fixed_put( GTK_FIXED(parent->widget), bl->widget, bl->realX, bl->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), bl->widget );
+ gtk_widget_set_uposition( bl->widget, bl->realX, bl->realY );
+#endif
+ gtkControlGetSize( (wControl_p)bl );
+ if (labelStr)
+ bl->labelW = gtkAddLabel( (wControl_p)bl, labelStr );
+ gtk_widget_show( bl->widget );
+ gtkAddButton( (wControl_p)bl );
+ gtkAddHelpString( bl->widget, helpStr );
+ return bl;
+}
diff --git a/app/wlib/gtklib/gtkmenu.c b/app/wlib/gtklib/gtkmenu.c
new file mode 100644
index 0000000..0782f02
--- /dev/null
+++ b/app/wlib/gtklib/gtkmenu.c
@@ -0,0 +1,873 @@
+/** \file gtkmenu.c
+ * Menu creation and handling stuff.
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkmenu.c,v 1.5 2009-10-03 04:49:01 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "gtkint.h"
+
+int testMenuPopup = 1;
+
+static char MenuItemDataKey[] = "MenuItemDataKey";
+
+extern char gtkAccelChar;
+
+/*
+ *****************************************************************************
+ *
+ * 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;
+
+
+#define MOBJ_COMMON \
+ WOBJ_COMMON \
+ mtype_e mtype; \
+ GtkWidget * menu_item; \
+ wMenu_p parentMenu; \
+ int recursion;
+
+struct wMenuItem_t {
+ MOBJ_COMMON
+ };
+typedef struct wMenuItem_t * wMenuItem_p;
+
+struct wMenu_t {
+ MOBJ_COMMON
+ mmtype_e mmtype;
+ wMenuItem_p first, last;
+ GSList *radioGroup; /* in case menu holds a radio button group */
+ GtkWidget * menu;
+ wMenuTraceCallBack_p traceFunc;
+ void * traceData;
+ GtkLabel * labelG;
+ GtkWidget * imageG;
+ };
+
+struct wMenuPush_t {
+ MOBJ_COMMON
+ wMenuCallBack_p action;
+ wBool_t enabled;
+ };
+
+struct wMenuRadio_t {
+ MOBJ_COMMON
+ wMenuCallBack_p action;
+ wBool_t enabled;
+ };
+
+
+typedef struct wMenuListItem_t * wMenuListItem_p;
+
+struct wMenuList_t {
+ MOBJ_COMMON
+ int max;
+ int count;
+ wMenuListCallBack_p action;
+ };
+
+struct wMenuListItem_t {
+ MOBJ_COMMON
+ wMenuList_p mlist;
+ };
+
+struct wMenuToggle_t {
+ MOBJ_COMMON
+ wMenuToggleCallBack_p action;
+ wBool_t enabled;
+ wBool_t set;
+ };
+
+
+/*-----------------------------------------------------------------*/
+
+static void pushMenuItem(
+ GtkWidget * widget,
+ gpointer value )
+{
+ wMenuItem_p m = (wMenuItem_p)value;
+ wMenuToggle_p mt;
+ if (gdk_pointer_is_grabbed()) {
+ gdk_pointer_ungrab(0);
+ }
+/* wFlush(); */
+ if (m->recursion)
+ return;
+ switch (m->mtype) {
+ case M_PUSH:
+ if ( ((wMenuPush_p)m)->enabled == FALSE )
+ wBeep();
+ else
+ ((wMenuPush_p)m)->action( ((wMenuPush_p)m)->data );
+ break;
+ case M_TOGGLE:
+ mt = (wMenuToggle_p)m;
+ if ( mt->enabled == FALSE ) {
+ wBeep();
+ } else {
+ wMenuToggleSet( mt, !mt->set );
+ mt->action( mt->set, mt->data );
+ }
+ break;
+ case M_RADIO:
+ /* NOTE: action is only called when radio button is activated, not when deactivated */
+ if ( ((wMenuRadio_p)m)->enabled == FALSE )
+ wBeep();
+ else
+ if( ((GtkCheckMenuItem *)widget)->active == TRUE )
+ ((wMenuRadio_p)m)->action( ((wMenuRadio_p)m)->data );
+ break;
+ case M_MENU:
+ return;
+ default:
+ /*fprintf(stderr," Oops menu\n");*/
+ return;
+ }
+ if ( (m->parentMenu)->traceFunc ) {
+ (m->parentMenu)->traceFunc( m->parentMenu, m->labelStr, ((wMenu_p)m->parentMenu)->traceData );
+ }
+}
+
+static wMenuItem_p createMenuItem(
+ wMenu_p m,
+ mtype_e mtype,
+ const char * helpStr,
+ const char * labelStr,
+ int size )
+{
+ wMenuItem_p mi;
+ mi = (wMenuItem_p)gtkAlloc( NULL, B_MENUITEM, 0, 0, labelStr, size, NULL );
+ mi->mtype = mtype;
+ switch ( mtype ) {
+ case M_LIST:
+ m->menu_item = NULL;
+ break;
+ case M_SEPARATOR:
+ mi->menu_item = gtk_separator_menu_item_new();
+ break;
+ case M_TOGGLE:
+ mi->menu_item = gtk_check_menu_item_new_with_mnemonic(gtkConvertInput(mi->labelStr));
+ break;
+ case M_RADIO:
+ mi->menu_item = gtk_radio_menu_item_new_with_mnemonic(m->radioGroup, gtkConvertInput(mi->labelStr));
+ m->radioGroup = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (mi->menu_item));
+ break;
+ default:
+ mi->menu_item = gtk_menu_item_new_with_mnemonic(gtkConvertInput(mi->labelStr));
+ break;
+ }
+ if (mi->menu_item) {
+ if (m)
+ gtk_menu_append( GTK_MENU(m->menu), mi->menu_item );
+
+ gtk_signal_connect( GTK_OBJECT(mi->menu_item), "activate",
+ GTK_SIGNAL_FUNC(pushMenuItem), mi );
+ gtk_widget_show(mi->menu_item);
+ }
+ if (m) {
+ if (m->first == NULL) {
+ m->first = mi;
+ } else {
+ m->last->next = (wControl_p)mi;
+ }
+ m->last = mi;
+ }
+ mi->next = NULL;
+ if (helpStr != NULL) {
+ gtkAddHelpString( mi->menu_item, helpStr );
+ }
+ mi->parentMenu = m;
+ return mi;
+}
+
+
+static void setAcclKey( wWin_p w, GtkWidget * menu, GtkWidget * menu_item, int acclKey )
+{
+ char acclStr[40];
+ int len;
+ int mask;
+ static GtkAccelGroup * accel_alpha_group = NULL;
+ static GtkAccelGroup * accel_nonalpha_group = NULL;
+ guint oldmods;
+
+
+ if (accel_alpha_group == NULL) {
+ accel_alpha_group = gtk_accel_group_new();
+ /*gtk_accel_group_set_mod_mask( accel_group, GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_MOD1_MASK );*/
+ gtk_window_add_accel_group(GTK_WINDOW(gtkMainW->gtkwin), accel_alpha_group );
+ }
+ if (accel_nonalpha_group == NULL) {
+ oldmods = gtk_accelerator_get_default_mod_mask();
+ gtk_accelerator_set_default_mod_mask( GDK_CONTROL_MASK | GDK_MOD1_MASK );
+ accel_nonalpha_group = gtk_accel_group_new();
+ /*gtk_accel_group_set_mod_mask( accel_group, GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_MOD1_MASK );*/
+ gtk_window_add_accel_group(GTK_WINDOW(gtkMainW->gtkwin), accel_nonalpha_group );
+ gtk_accelerator_set_default_mod_mask( oldmods );
+ }
+
+ mask = 0;
+ if (acclKey) {
+#ifdef LATER
+ switch ( (acclKey&0xFF) ) {
+ case '+': acclKey = (acclKey&0xFF00) | WSHIFT | '='; break;
+ case '?': acclKey = (acclKey&0xFF00) | WSHIFT | '/'; break;
+ }
+#endif
+ len = 0;
+ if (acclKey&WALT) {
+ mask |= GDK_MOD1_MASK;
+ strcpy( acclStr+len, "Meta+" );
+ len += 5;
+ }
+ if (acclKey&WSHIFT) {
+ mask |= GDK_SHIFT_MASK;
+ strcpy( acclStr+len, "Shift+" );
+ len += 6;
+ switch ( (acclKey&0xFF) ) {
+ case '0': acclKey += ')'-'0'; break;
+ case '1': acclKey += '!'-'1'; break;
+ case '2': acclKey += '@'-'2'; break;
+ case '3': acclKey += '#'-'3'; break;
+ case '4': acclKey += '$'-'4'; break;
+ case '5': acclKey += '%'-'5'; break;
+ case '6': acclKey += '^'-'6'; break;
+ case '7': acclKey += '&'-'7'; break;
+ case '8': acclKey += '*'-'8'; break;
+ case '9': acclKey += '('-'9'; break;
+ case '`': acclKey += '~'-'`'; break;
+ case '-': acclKey += '_'-'-'; break;
+ case '=': acclKey += '+'-'='; break;
+ case '\\': acclKey += '|'-'\\'; break;
+ case '[': acclKey += '{'-'['; break;
+ case ']': acclKey += '}'-']'; break;
+ case ';': acclKey += ':'-';'; break;
+ case '\'': acclKey += '"'-'\''; break;
+ case ',': acclKey += '<'-','; break;
+ case '.': acclKey += '>'-'.'; break;
+ case '/': acclKey += '?'-'/'; break;
+ default: break;
+ }
+ }
+ if (acclKey&WCTL) {
+ mask |= GDK_CONTROL_MASK;
+ strcpy( acclStr+len, "Ctrl+" );
+ len += 5;
+ }
+ acclStr[len++] = (acclKey & 0xFF);
+ acclStr[len++] = '\0';
+ gtk_widget_add_accelerator( menu_item, "activate",
+ (isalpha(acclKey&0xFF)?accel_alpha_group:accel_nonalpha_group),
+ toupper(acclKey&0xFF), mask, GTK_ACCEL_VISIBLE|GTK_ACCEL_LOCKED );
+ }
+}
+
+/*-----------------------------------------------------------------*/
+
+wMenuRadio_p wMenuRadioCreate(
+ wMenu_p m,
+ const char * helpStr,
+ const char * labelStr,
+ long acclKey,
+ wMenuCallBack_p action,
+ void *data )
+{
+ wMenuRadio_p mi;
+
+ mi = (wMenuRadio_p)createMenuItem( m, M_RADIO, helpStr, labelStr, sizeof *mi );
+ if (m->mmtype == MM_POPUP && !testMenuPopup)
+ return mi;
+ setAcclKey( m->parent, m->menu, mi->menu_item, acclKey );
+ mi->action = action;
+ mi->data = data;
+ mi->enabled = TRUE;
+ return mi;
+}
+
+void wMenuRadioSetActive(
+ wMenuRadio_p mi )
+{
+ gtk_check_menu_item_set_active( (GtkCheckMenuItem *)mi->menu_item, TRUE );
+}
+
+/*-----------------------------------------------------------------*/
+
+wMenuPush_p wMenuPushCreate(
+ wMenu_p m,
+ const char * helpStr,
+ const char * labelStr,
+ long acclKey,
+ wMenuCallBack_p action,
+ void *data )
+{
+ wMenuPush_p mi;
+
+ mi = (wMenuPush_p)createMenuItem( m, M_PUSH, helpStr, labelStr, sizeof *mi );
+ if (m->mmtype == MM_POPUP && !testMenuPopup)
+ return mi;
+ setAcclKey( m->parent, m->menu, mi->menu_item, acclKey );
+ mi->action = action;
+ mi->data = data;
+ mi->enabled = TRUE;
+ return mi;
+}
+
+
+void wMenuPushEnable(
+ wMenuPush_p mi,
+ wBool_t enable )
+{
+ mi->enabled = enable;
+ gtk_widget_set_sensitive( GTK_WIDGET(mi->menu_item), enable );
+}
+
+
+/*-----------------------------------------------------------------*/
+
+wMenu_p wMenuMenuCreate(
+ wMenu_p m,
+ const char * helpStr,
+ const char * labelStr )
+{
+ wMenu_p mi;
+ mi = (wMenu_p)createMenuItem( m, M_MENU, helpStr, labelStr, sizeof *mi );
+ mi->mmtype = MM_MENU;
+ mi->menu = gtk_menu_new();
+ /*gtk_widget_set_sensitive( GTK_WIDGET(mi->menu_item), FALSE );*/
+ gtk_menu_item_set_submenu( GTK_MENU_ITEM(mi->menu_item), mi->menu );
+ return mi;
+}
+
+
+/*-----------------------------------------------------------------*/
+
+void wMenuSeparatorCreate(
+ wMenu_p m )
+{
+ wMenuItem_p mi;
+ mi = createMenuItem( m, M_SEPARATOR, NULL, "", sizeof *mi );
+}
+
+
+/*-----------------------------------------------------------------*/
+
+int getMlistOrigin( wMenu_p m, wMenuList_p ml )
+{
+ wMenuItem_p mi;
+ int count;
+ count = 0; /* Menu counts as one */
+ for ( mi = m->first; mi != NULL; mi = (wMenuItem_p)mi->next ) {
+ 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:
+ /*fprintf(stderr, "Oops: getMlistOrigin\n");*/
+ break;
+ }
+ }
+ return count;
+}
+
+wMenuList_p wMenuListCreate(
+ wMenu_p m,
+ const char * helpStr,
+ int max,
+ wMenuListCallBack_p action )
+{
+ wMenuList_p mi;
+ mi = (wMenuList_p)createMenuItem( m, M_LIST, NULL, NULL, sizeof *mi );
+ mi->next = NULL;
+ mi->count = 0;
+ mi->max = max;
+ mi->parentMenu = m;
+ mi->action = action;
+ return (wMenuList_p)mi;
+}
+
+
+static void pushMenuList(
+ GtkWidget * widget,
+ gpointer value )
+{
+ wMenuListItem_p ml = (wMenuListItem_p)value;
+ int i;
+ int origin;
+ GtkWidget * item;
+ char * itemLabel;
+ GList * children;
+ GList * child;
+ GtkWidget *label;
+
+ if (gdk_pointer_is_grabbed()) {
+ gdk_pointer_ungrab(0);
+ }
+ wFlush();
+
+ if (ml->recursion)
+ return;
+ if (ml->mlist->count <= 0) {
+ fprintf( stderr, "pushMenuItem: empty list\n" );
+ return;
+ }
+ if (ml->mlist->action) {
+ origin = getMlistOrigin(ml->mlist->parentMenu, ml->mlist);
+ children = gtk_container_children( GTK_CONTAINER(ml->mlist->parentMenu->menu) );
+ if (children == NULL) abort();
+ child = g_list_nth( children, origin );
+ for (i=origin; i<origin+ml->mlist->count; i++, child=g_list_next(child) ) {
+ if (child == NULL) abort();
+ item = (GtkWidget*)child->data;
+ if (item == NULL) abort();
+ if (item == widget) {
+ children = gtk_container_children(GTK_CONTAINER(item));
+ label = (GtkWidget*)children->data;
+ gtk_label_get( GTK_LABEL(label), &itemLabel );
+ ml->mlist->action( i-origin, itemLabel, ml->data );
+ return;
+ }
+ }
+ }
+ fprintf( stderr, "pushMenuItem: item (%lx) not found\n", (long)widget );
+}
+
+
+void wMenuListAdd(
+ wMenuList_p ml,
+ int index,
+ const char * labelStr,
+ const void * data )
+{
+ int i;
+ int origin;
+ GtkWidget * item;
+ char * itemLabel;
+ GList * children;
+ GList * child;
+ GList * itemList;
+ GtkWidget * label;
+ wMenuListItem_p mi;
+ char * labelStrConverted;
+
+ origin = getMlistOrigin(ml->parentMenu, ml);
+ if (ml->count > 0) {
+ children = gtk_container_children( GTK_CONTAINER(ml->parentMenu->menu) );
+ if (children == NULL) abort();
+ child = g_list_nth( children, origin );
+ labelStrConverted = gtkConvertInput(labelStr);
+ for (i=origin; i<origin+ml->count; i++, child=g_list_next(child) ) {
+ if (child == NULL) abort();
+ item = (GtkWidget*)child->data;
+ if (item == NULL) abort();
+ itemList = gtk_container_children(GTK_CONTAINER(item));
+ label = (GtkWidget*)itemList->data;
+ gtk_label_get( GTK_LABEL(label), &itemLabel );
+ if (strcmp( labelStrConverted, itemLabel ) == 0) {
+ if (i != ml->count+index) {
+ gtk_container_remove( GTK_CONTAINER(ml->parentMenu->menu), item );
+ ml->count--;
+ break;
+ }
+ return;
+ }
+ }
+ if (ml->max >= 0 && ml->count >= ml->max) {
+ child = g_list_nth( children, origin+ml->count-1 );
+ if (child == NULL) abort();
+ item = (GtkWidget*)child->data;
+ if (item == NULL) abort();
+ gtk_container_remove( GTK_CONTAINER(ml->parentMenu->menu), item );
+ ml->count--;
+ }
+ }
+ mi = (wMenuListItem_p)gtkAlloc( NULL, B_MENUITEM, 0, 0, labelStr, sizeof *mi, NULL );
+ mi->mtype = M_LISTITEM;
+ mi->menu_item = gtk_menu_item_new_with_label(gtkConvertInput(mi->labelStr));
+ mi->data = (void *)data;
+ mi->mlist = ml;
+ if (index < 0 || index > ml->count)
+ index = ml->count;
+ gtk_menu_insert( GTK_MENU(ml->parentMenu->menu), mi->menu_item, origin+index );
+ gtk_signal_connect( GTK_OBJECT(mi->menu_item), "activate",
+ GTK_SIGNAL_FUNC(pushMenuList), mi );
+ gtk_object_set_data( GTK_OBJECT(mi->menu_item), MenuItemDataKey, mi );
+ gtk_widget_show(mi->menu_item);
+
+ ml->count++;
+}
+
+
+void wMenuListDelete(
+ wMenuList_p ml,
+ const char * labelStr )
+{
+ int i;
+ int origin;
+ GtkWidget * item;
+ char * itemLabel;
+ GList * children;
+ GList * child;
+ GtkWidget * label;
+ char * labelStrConverted;
+
+ if (ml->count <= 0) abort();
+ origin = getMlistOrigin(ml->parentMenu, ml);
+ children = gtk_container_children( GTK_CONTAINER(ml->parentMenu->menu) );
+ if (children == NULL) abort();
+ child = g_list_nth( children, origin );
+ labelStrConverted = gtkConvertInput( labelStr );
+ for (i=origin; i<origin+ml->count; i++, child=g_list_next(child) ) {
+ if (child == NULL) abort();
+ item = (GtkWidget*)child->data;
+ if (item == NULL) abort();
+ children = gtk_container_children(GTK_CONTAINER(item));
+ label = (GtkWidget*)children->data;
+ gtk_label_get( GTK_LABEL(label), &itemLabel );
+ if (strcmp( labelStrConverted, itemLabel ) == 0) {
+ gtk_container_remove( GTK_CONTAINER(ml->parentMenu->menu), item );
+ gtk_widget_queue_resize( GTK_WIDGET(ml->parentMenu->menu) );
+ ml->count--;
+ return;
+ }
+ }
+}
+
+
+const char * wMenuListGet( wMenuList_p ml, int index, void ** data )
+{
+ int origin;
+ GtkWidget * item;
+ GList * children;
+ GList * child;
+ GtkWidget * label;
+ char * itemLabel;
+ wMenuListItem_p mi;
+
+ if (ml->count <= 0)
+ return NULL;
+
+ if (index >= ml->count) {
+ if (data)
+ *data = NULL;
+ return NULL;
+ }
+ origin = getMlistOrigin(ml->parentMenu, ml);
+ children = gtk_container_children( GTK_CONTAINER(ml->parentMenu->menu) );
+ if (children == NULL) abort();
+ child = g_list_nth( children, origin+index );
+ if (child == NULL) abort();
+ item = (GtkWidget*)child->data;
+ if (item == NULL) abort();
+ children = gtk_container_children(GTK_CONTAINER(item));
+ label = (GtkWidget*)children->data;
+ gtk_label_get( GTK_LABEL(label), &itemLabel );
+ if (data) {
+ mi = (wMenuListItem_p)gtk_object_get_data( GTK_OBJECT(item), MenuItemDataKey );
+ if (mi)
+ *data = mi->data;
+ }
+ return itemLabel;
+}
+
+
+void wMenuListClear(
+ wMenuList_p ml )
+{
+ int i;
+ int origin;
+ GtkWidget * item;
+ GList * children;
+ GList * child;
+
+ if (ml->count == 0)
+ return;
+ origin = getMlistOrigin(ml->parentMenu, ml);
+ children = gtk_container_children( GTK_CONTAINER(ml->parentMenu->menu) );
+ if (children == NULL) abort();
+ child = g_list_nth( children, origin );
+ for (i=origin; i<origin+ml->count; i++, child=g_list_next(child) ) {
+ if (child == NULL) abort();
+ item = (GtkWidget*)child->data;
+ if (item == NULL) abort();
+ gtk_container_remove( GTK_CONTAINER(ml->parentMenu->menu), item );
+ }
+ ml->count = 0;
+ gtk_widget_queue_resize( GTK_WIDGET(ml->parentMenu->menu) );
+}
+/*-----------------------------------------------------------------*/
+
+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;
+
+ 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->enabled = TRUE;
+ mt->parentMenu = m;
+ wMenuToggleSet( mt, set );
+
+ return mt;
+}
+
+
+wBool_t wMenuToggleGet(
+ wMenuToggle_p mt )
+{
+ return mt->set;
+}
+
+
+wBool_t wMenuToggleSet(
+ wMenuToggle_p mt,
+ wBool_t set )
+{
+ wBool_t rc;
+ if (mt==NULL) return 0;
+ mt->recursion++;
+ gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM(mt->menu_item), set );
+ mt->recursion--;
+ rc = mt->set;
+ mt->set = set;
+ return rc;
+}
+
+
+void wMenuToggleEnable(
+ wMenuToggle_p mt,
+ wBool_t enable )
+{
+ mt->enabled = enable;
+}
+
+
+/*-----------------------------------------------------------------*/
+
+void wMenuSetLabel( wMenu_p m, const char * labelStr) {
+ gtkSetLabel( m->widget, m->option, labelStr, &m->labelG, &m->imageG );
+}
+
+
+static gint pushMenu(
+ GtkWidget * widget,
+ wMenu_p m )
+{
+ gtk_menu_popup( GTK_MENU(m->menu), NULL, NULL, NULL, NULL, 0, 0 );
+ /* Tell calling code that we have handled this event; the buck
+ * stops here. */
+ return TRUE;
+}
+
+
+wMenu_p wMenuCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ long option )
+{
+ wMenu_p m;
+ m = gtkAlloc( parent, B_MENU, x, y, labelStr, sizeof *m, NULL );
+ m->mmtype = MM_BUTT;
+ m->option = option;
+ m->traceFunc = NULL;
+ m->traceData = NULL;
+ gtkComputePos( (wControl_p)m );
+
+ m->widget = gtk_button_new();
+ gtk_signal_connect (GTK_OBJECT(m->widget), "clicked",
+ GTK_SIGNAL_FUNC(pushMenu), m );
+
+ m->menu = gtk_menu_new();
+
+ wMenuSetLabel( m, labelStr );
+#ifdef MENUOPTION
+ gtk_option_menu_set_menu( GTK_OPTION_MENU(m->widget), m->menu );
+ ((GtkOptionMenu*)m->widget)->width = 25;
+ ((GtkOptionMenu*)m->widget)->height = 16;
+#endif
+
+ gtk_fixed_put( GTK_FIXED(parent->widget), m->widget, m->realX, m->realY );
+ gtkControlGetSize( (wControl_p)m );
+ if ( m->w < 80 && (m->option&BO_ICON)==0) {
+ m->w = 80;
+ gtk_widget_set_usize( m->widget, m->w, m->h );
+ }
+ gtk_widget_show( m->widget );
+ gtkAddButton( (wControl_p)m );
+ gtkAddHelpString( m->widget, helpStr );
+ return m;
+}
+
+/**
+ * Add a drop-down menu to the menu bar.
+ *
+ * \param[IN] w main window handle
+ * \param[IN] helpStr unused (should be help topic )
+ * \param[IN] labelStr label for the drop-down menu
+ * \return pointer to the created drop-down menu
+ */
+
+
+wMenu_p wMenuBarAdd(
+ wWin_p w,
+ const char * helpStr,
+ const char * labelStr )
+{
+ wMenu_p m;
+ GtkWidget * menuItem;
+ static GtkAccelGroup * accel_group = NULL;
+
+ m = gtkAlloc( w, B_MENU, 0, 0, labelStr, sizeof *m, NULL );
+ m->mmtype = MM_BAR;
+ m->realX = 0;
+ m->realY = 0;
+
+ menuItem = gtk_menu_item_new_with_label( gtkConvertInput(m->labelStr) );
+ m->menu = gtk_menu_new();
+ gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), m->menu );
+ gtk_menu_bar_append( GTK_MENU_BAR(w->menubar), menuItem );
+ gtk_widget_show( menuItem );
+
+ m->w = 0;
+ m->h = 0;
+
+ /* TODO: why is help not supported here? */
+ /*gtkAddHelpString( m->panel_item, helpStr );*/
+
+ if ( gtkAccelChar ) {
+ if ( accel_group == NULL ) {
+ accel_group = gtk_accel_group_new();
+ gtk_window_add_accel_group( GTK_WINDOW(w->gtkwin), accel_group );
+ }
+ gtk_widget_add_accelerator( menuItem, "activate", accel_group, tolower(gtkAccelChar), GDK_MOD1_MASK, GTK_ACCEL_LOCKED );
+ }
+ return m;
+}
+
+
+/*-----------------------------------------------------------------*/
+
+
+wMenu_p wMenuPopupCreate(
+ wWin_p w,
+ const char * labelStr )
+{
+ wMenu_p b;
+ b = gtkAlloc( w, B_MENU, 0, 0, labelStr, sizeof *b, NULL );
+ b->mmtype = MM_POPUP;
+ b->option = 0;
+
+ b->menu = gtk_menu_new();
+ b->w = 0;
+ b->h = 0;
+ gtk_signal_connect( GTK_OBJECT (b->menu), "key_press_event",
+ GTK_SIGNAL_FUNC (catch_shift_ctrl_alt_keys), b);
+ gtk_signal_connect( GTK_OBJECT (b->menu), "key_release_event",
+ GTK_SIGNAL_FUNC (catch_shift_ctrl_alt_keys), b);
+ gtk_widget_set_events ( GTK_WIDGET(b->menu), GDK_EXPOSURE_MASK|GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK );
+ return b;
+}
+
+
+void wMenuPopupShow( wMenu_p mp )
+{
+ gtk_menu_popup( GTK_MENU(mp->menu), NULL, NULL, NULL, NULL, 0, 0 );
+}
+
+
+/*-----------------------------------------------------------------*/
+
+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;
+ for ( mi = m->first; mi != NULL; mi = (wMenuItem_p)mi->next ) {
+ if ( 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 {
+ wMenuToggleSet( mt, !mt->set );
+ mt->action( mt->set, mt->data );
+ }
+ break;
+ case M_MENU:
+ break;
+ case M_LIST:
+ break;
+ default:
+ /*fprintf(stderr, "Oops: wMenuAction\n");*/
+ break;
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/app/wlib/gtklib/gtkmisc.c b/app/wlib/gtklib/gtkmisc.c
new file mode 100644
index 0000000..acc123a
--- /dev/null
+++ b/app/wlib/gtklib/gtkmisc.c
@@ -0,0 +1,1210 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkmisc.c,v 1.15 2009-10-03 04:49:01 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gtkint.h"
+#include "i18n.h"
+
+wWin_p gtkMainW;
+
+long debugWindow = 0;
+
+char wAppName[256];
+char wConfigName[ 256 ];
+
+#define FOUR (4)
+#ifndef GTK1
+#define MENUH (24)
+#else
+#define MENUH (24)
+#endif
+#define LABEL_OFFSET (3)
+
+const char * wNames[] = {
+ "MAIN",
+ "POPUP",
+ "BUTT",
+ "CANCEL",
+ "POPUP",
+ "TEXT",
+ "INTEGER",
+ "FLOAT",
+ "LIST",
+ "DROPLIST",
+ "COMBOLIST",
+ "RADIO",
+ "TOGGLE",
+ "DRAW",
+ "MENU"
+ "MULTITEXT",
+ "MESSAGE",
+ "LINES",
+ "MENUITEM",
+ "BOX"
+ };
+
+static struct timeval startTime;
+
+static wBool_t reverseIcon =
+#if defined(linux)
+ FALSE;
+#else
+ TRUE;
+#endif
+
+char gtkAccelChar;
+
+
+/*
+ *****************************************************************************
+ *
+ * Internal Utility functions
+ *
+ *****************************************************************************
+ */
+
+unsigned char gtkBitrotate(
+ char v )
+{
+ unsigned char r = 0;
+ int i;
+ static unsigned char bits[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+ for (i=0;i<8;i++)
+ if (v & bits[i])
+ r |= bits[7-i];
+ return r;
+}
+
+GdkPixmap* gtkMakeIcon(
+ GtkWidget * widget,
+ wIcon_p ip,
+ GdkBitmap ** mask )
+{
+ GdkPixmap * pixmap;
+ char ** pixmapData;
+ char * oldline1;
+ static char newline1[] = " \tc None s None";
+ char line0[40];
+ char line2[40];
+ int row,col,wb;
+ long rgb;
+ const char * bits;
+ GdkColor *transparent;
+
+ transparent = &gtk_widget_get_style( gtkMainW->gtkwin )->bg[GTK_WIDGET_STATE( gtkMainW->gtkwin )];
+
+ if ( ip->gtkIconType == gtkIcon_pixmap ) {
+ pixmap = gdk_pixmap_create_from_xpm_d( gtkMainW->gtkwin->window, mask, transparent, (char**)ip->bits );
+ }
+ else {
+ wb = (ip->w+7)/8;
+ pixmapData = (char**)malloc( (3+ip->h) * sizeof *pixmapData );
+ pixmapData[0] = line0;
+ rgb = wDrawGetRGB(ip->color);
+ sprintf( line0, " %d %d 2 1", ip->w, ip->h );
+ sprintf( line2, "# c #%2.2lx%2.2lx%2.2lx", (rgb>>16)&0xFF, (rgb>>8)&0xFF, rgb&0xFF );
+ pixmapData[1] = ". c None s None";
+ pixmapData[2] = line2;
+ bits = ip->bits;
+ for (row = 0; row<ip->h; row++ ) {
+ pixmapData[row+3] = (char*)malloc( (ip->w+1) * sizeof **pixmapData );
+ for (col = 0; col<ip->w; col++ ) {
+ if ( bits[ row*wb+(col>>3) ] & (1<<(col&07)) ) {
+ pixmapData[row+3][col] = '#';
+ } else {
+ pixmapData[row+3][col] = '.';
+ }
+ }
+ pixmapData[row+3][ip->w] = 0;
+ }
+ pixmap = gdk_pixmap_create_from_xpm_d( gtkMainW->gtkwin->window, mask, transparent, pixmapData );
+ for (row = 0; row<ip->h; row++ ) {
+ free( pixmapData[row+3] );
+ }
+ }
+ return pixmap;
+}
+
+
+int gtkAddLabel( wControl_p b, const char * labelStr )
+{
+ GtkRequisition requisition;
+ if (labelStr == NULL)
+ return 0;
+ b->label = gtk_label_new(gtkConvertInput(labelStr));
+ gtk_widget_size_request( b->label, &requisition );
+ gtk_container_add( GTK_CONTAINER(b->parent->widget), b->label );
+#ifndef GTK1
+ gtk_fixed_move( GTK_FIXED(b->parent->widget), b->label, b->realX-requisition.width-8, b->realY+LABEL_OFFSET );
+#else
+ gtk_widget_set_uposition( b->label, b->realX-requisition.width-8, b->realY+LABEL_OFFSET );
+#endif
+ gtk_widget_show( b->label );
+ return requisition.width+8;
+}
+
+
+void * gtkAlloc(
+ wWin_p parent,
+ wType_e type,
+ wPos_t origX,
+ wPos_t origY,
+ const char * labelStr,
+ int size,
+ void * data )
+{
+ wControl_p w = (wControl_p)malloc( size );
+ char * cp;
+ memset( w, 0, size );
+ if (w == NULL)
+ abort();
+ w->type = type;
+ w->parent = parent;
+ w->origX = origX;
+ w->origY = origY;
+ gtkAccelChar = 0;
+ if (labelStr) {
+ cp = (char*)malloc(strlen(labelStr)+1);
+ w->labelStr = cp;
+ for ( ; *labelStr; labelStr++ )
+ if ( *labelStr != '&' )
+ *cp++ = *labelStr;
+ else {
+/* *cp++ = '_';
+ gtkAccelChar = labelStr[1]; */
+ }
+ *cp = 0;
+ }
+ w->doneProc = NULL;
+ w->data = data;
+ return w;
+}
+
+
+void gtkComputePos(
+ wControl_p b )
+{
+ wWin_p w = b->parent;
+
+ if (b->origX >= 0)
+ b->realX = b->origX;
+ else
+ b->realX = w->lastX + (-b->origX) - 1;
+ if (b->origY >= 0)
+ b->realY = b->origY + FOUR + ((w->option&F_MENUBAR)?MENUH:0);
+ else
+ b->realY = w->lastY + (-b->origY) - 1;
+}
+
+
+void gtkControlGetSize(
+ wControl_p b )
+{
+ GtkRequisition requisition;
+ gtk_widget_size_request( b->widget, &requisition );
+ b->w = requisition.width;
+ b->h = requisition.height;
+}
+
+
+void gtkAddButton(
+ wControl_p b )
+{
+ wWin_p win = b->parent;
+ wBool_t resize = FALSE;
+ if (win->first == NULL) {
+ win->first = b;
+ } else {
+ win->last->next = b;
+ }
+ win->last = b;
+ b->next = NULL;
+ b->parent = win;
+ win->lastX = b->realX + b->w;
+ win->lastY = b->realY + b->h;
+ if (win->option&F_AUTOSIZE) {
+ if (win->lastX > win->realX) {
+ win->realX = win->lastX;
+ if (win->w != (win->realX + win->origX)) {
+ resize = TRUE;
+ win->w = (win->realX + win->origX);
+ }
+ }
+ if (win->lastY > win->realY) {
+ win->realY = win->lastY;
+ if (win->h != (win->realY + win->origY)) {
+ resize = TRUE;
+ win->h = (win->realY + win->origY);
+ }
+ }
+ if (win->shown) {
+ if ( resize ) {
+#ifndef GTK1
+ gtk_widget_set_size_request( win->gtkwin, win->w, win->h );
+ gtk_widget_set_size_request( win->widget, win->w, win->h );
+#else
+ gtk_widget_set_usize( win->gtkwin, win->w, win->h );
+ gtk_widget_set_usize( win->widget, win->w, win->h );
+#endif
+ }
+ }
+ }
+}
+
+
+void gtkSetReadonly( wControl_p b, wBool_t ro )
+{
+ if (ro)
+ b->option |= BO_READONLY;
+ else
+ b->option &= ~BO_READONLY;
+}
+
+
+wControl_p gtkGetControlFromPos(
+ wWin_p win,
+ wPos_t x,
+ wPos_t y )
+{
+ wControl_p b;
+ wPos_t xx, yy;
+ for (b=win->first; b != NULL; b = b->next) {
+ if ( b->widget && GTK_WIDGET_VISIBLE(b->widget) ) {
+ xx = b->realX;
+ yy = b->realY;
+ if ( xx <= x && x < xx+b->w &&
+ yy <= y && y < yy+b->h ) {
+ return b;
+ }
+ }
+ }
+ return NULL;
+}
+
+/* \brief Convert label string from Windows mnemonic to GTK
+ *
+ * The first occurence of '&' in the passed string is changed to '_'
+ *
+ * \param label the string to convert
+ * \return pointer to modified string, has to be free'd after usage
+ *
+ */
+static
+char * gtkChgMnemonic( char *label )
+{
+ char *ptr;
+ char *cp;
+
+ cp = strdup( label );
+
+ ptr = strchr( cp, '&' );
+ if( ptr )
+ *ptr = '_';
+
+ return( cp );
+}
+
+
+/*
+ *****************************************************************************
+ *
+ * Exported Utility Functions
+ *
+ *****************************************************************************
+ */
+
+EXPORT void wBeep(
+ void )
+/*
+Beep!
+*/
+{
+ gdk_display_beep(gdk_display_get_default());
+}
+
+typedef struct {
+ GtkWidget * win;
+ GtkWidget * label;
+ GtkWidget * butt[3];
+ } notice_win;
+static notice_win noticeW;
+static long noticeValue;
+
+static void doNotice(
+ GtkWidget * widget,
+ long value )
+{
+ noticeValue = value;
+ gtk_widget_destroy( noticeW.win );
+ gtkDoModal( NULL, FALSE );
+}
+
+/**
+ * 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;
+ unsigned flag;
+ char *headline;
+ GtkWidget *dialog;
+ GtkWindow *parent = GTK_WINDOW_TOPLEVEL;
+
+ switch( type ) {
+ case NT_INFORMATION:
+ flag = GTK_MESSAGE_INFO;
+ headline = _("Information");
+ break;
+ case NT_WARNING:
+ flag = GTK_MESSAGE_WARNING;
+ headline = _("Warning");
+ break;
+ case NT_ERROR:
+ flag = GTK_MESSAGE_ERROR;
+ headline = _("Error");
+ break;
+ }
+
+ if( gtkMainW )
+ parent = GTK_WINDOW( gtkMainW->gtkwin);
+
+ dialog = gtk_message_dialog_new( parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ flag,
+ ((no==NULL)?GTK_BUTTONS_OK:GTK_BUTTONS_YES_NO),
+ "%s", msg );
+ gtk_window_set_title( GTK_WINDOW(dialog), headline );
+
+ res = gtk_dialog_run( GTK_DIALOG(dialog));
+ gtk_widget_destroy( dialog );
+
+ return res == GTK_RESPONSE_OK || res == GTK_RESPONSE_YES;
+}
+
+
+EXPORT int wNotice(
+ const char * msg, /* Message */
+ const char * yes, /* First button label */
+ const char * no ) /* Second label (or 'NULL') */
+/*
+Popup up a notice box with one or two buttons.
+When this notice box is displayed the application is paused and
+will not response to other actions.
+
+Pushing the first button returns 'TRUE'.
+Pushing the second button (if present) returns 'FALSE'.
+*/
+{
+ return wNotice3( msg, yes, no, NULL );
+}
+
+/** \brief Popup a notice box with three buttons.
+ *
+ * Popup up a notice box with three buttons.
+ * When this notice box is displayed the application is paused and
+ * will not response to other actions.
+ *
+ * Pushing the first button returns 1
+ * Pushing the second button returns 0
+ * Pushing the third button returns -1
+ *
+ * \param msg Text to display in message box
+ * \param yes First button label
+ * \param no Second label (or 'NULL')
+ * \param cancel Third button label (or 'NULL')
+ *
+ * \returns 1, 0 or -1
+ */
+
+EXPORT int wNotice3(
+ const char * msg, /* Message */
+ const char * affirmative, /* First button label */
+ const char * cancel, /* Second label (or 'NULL') */
+ const char * alternate )
+{
+ notice_win *nw;
+ GtkWidget * vbox;
+ GtkWidget * hbox;
+ GtkWidget * hbox1;
+ GtkWidget * image;
+ nw = &noticeW;
+
+ char *aff = NULL;
+ char *can = NULL;
+ char *alt = NULL;
+
+#ifndef GTK1
+ nw->win = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ /*gtk_window_set_decorated( GTK_WINDOW(nw->win), FALSE );*/
+#else
+ nw->win = gtk_window_new( GTK_WINDOW_DIALOG );
+#endif
+ gtk_window_position( GTK_WINDOW(nw->win), GTK_WIN_POS_CENTER );
+ gtk_container_set_border_width (GTK_CONTAINER (nw->win), 0);
+ gtk_window_set_resizable (GTK_WINDOW (nw->win), FALSE);
+ gtk_window_set_modal (GTK_WINDOW (nw->win), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (nw->win), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ vbox = gtk_vbox_new( FALSE, 12 );
+ gtk_widget_show( vbox );
+ gtk_container_add( GTK_CONTAINER(nw->win), vbox );
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+
+ hbox = gtk_hbox_new( FALSE, 12 );
+ gtk_box_pack_start( GTK_BOX(vbox), hbox, TRUE, TRUE, 0 );
+ gtk_widget_show(hbox);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
+ gtk_widget_show (image);
+ gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 0);
+ gtk_misc_set_alignment (GTK_MISC (image), 0, 0);
+
+ /* create the text label, allow GTK to wrap and allow for markup (for future enhancements) */
+ nw->label = gtk_label_new(msg);
+ gtk_widget_show( nw->label );
+ gtk_box_pack_end (GTK_BOX (hbox), nw->label, TRUE, TRUE, 0);
+ gtk_label_set_use_markup (GTK_LABEL (nw->label), FALSE);
+ gtk_label_set_line_wrap (GTK_LABEL (nw->label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (nw->label), 0, 0);
+
+ /* this hbox will include the button bar */
+ hbox1 = gtk_hbox_new (TRUE, 0);
+ gtk_widget_show (hbox1);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox1, FALSE, TRUE, 0);
+
+ /* add the respective buttons */
+ aff = gtkChgMnemonic( (char *) affirmative);
+ nw->butt[ 0 ] = gtk_button_new_with_mnemonic (aff);
+ gtk_widget_show (nw->butt[ 0 ]);
+ gtk_box_pack_end (GTK_BOX (hbox1), nw->butt[ 0 ], TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (nw->butt[ 0 ]), 3);
+ gtk_signal_connect( GTK_OBJECT(nw->butt[0]), "clicked", GTK_SIGNAL_FUNC(doNotice), (void*)1 );
+ GTK_WIDGET_SET_FLAGS (nw->butt[ 0 ], GTK_CAN_DEFAULT);
+
+ if( cancel ) {
+ can = gtkChgMnemonic( (char *) cancel);
+ nw->butt[ 1 ] = gtk_button_new_with_mnemonic (can);
+ gtk_widget_show (nw->butt[ 1 ]);
+ gtk_box_pack_end (GTK_BOX (hbox1), nw->butt[ 1 ], TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (nw->butt[ 1 ]), 3);
+ gtk_signal_connect( GTK_OBJECT(nw->butt[1]), "clicked", GTK_SIGNAL_FUNC(doNotice), (void*)0 );
+ GTK_WIDGET_SET_FLAGS (nw->butt[ 1 ], GTK_CAN_DEFAULT);
+
+ if( alternate ) {
+ alt = gtkChgMnemonic( (char *) alternate);
+ nw->butt[ 2 ] = gtk_button_new_with_mnemonic (alt);
+ gtk_widget_show (nw->butt[ 2 ]);
+ gtk_box_pack_start (GTK_BOX (hbox1), nw->butt[ 2 ], TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (nw->butt[ 2 ]), 3);
+ gtk_signal_connect( GTK_OBJECT(nw->butt[2]), "clicked", GTK_SIGNAL_FUNC(doNotice), (void*)-1 );
+ GTK_WIDGET_SET_FLAGS (nw->butt[ 2 ], GTK_CAN_DEFAULT);
+ }
+ }
+
+ gtk_widget_grab_default (nw->butt[ 0 ]);
+ gtk_widget_grab_focus (nw->butt[ 0 ]);
+
+ gtk_widget_show( nw->win );
+
+ if ( gtkMainW ) {
+ gtk_window_set_transient_for( GTK_WINDOW(nw->win), GTK_WINDOW( gtkMainW->gtkwin) );
+/* gdk_window_set_group( nw->win->window, gtkMainW->gtkwin->window ); */
+ }
+ gtkDoModal( NULL, TRUE );
+
+ if( aff )
+ free( aff );
+
+ if( can )
+ free( can );
+
+ if( alt )
+ free( alt );
+
+ return noticeValue;
+}
+
+
+EXPORT void wFlush(
+ void )
+/*
+Flushs all commands to the Window.
+*/
+{
+ while ( gtk_events_pending() )
+ gtk_main_iteration();
+
+ gdk_display_sync(gdk_display_get_default());
+}
+
+
+void wWinTop( wWin_p win )
+{
+}
+
+
+void wSetCursor( wCursor_t cursor )
+{
+}
+
+
+const char * wMemStats( void )
+{
+#ifdef LATER
+ static char msg[80];
+ struct mstats stats;
+ stats = mstats();
+ sprintf( msg, "Total %d, used %d(%d), free %d(%d)",
+ stats.bytes_total,
+ stats.bytes_used, stats.chunks_used,
+ stats.bytes_free, stats.chunks_free );
+ return msg;
+#else
+ return "No stats available";
+#endif
+}
+
+
+wBool_t wCheckExecutable( void )
+{
+ return TRUE;
+}
+
+
+void wGetDisplaySize( wPos_t * w, wPos_t * h )
+{
+
+ *w = gdk_screen_width();
+ *h = gdk_screen_height();
+}
+
+
+wIcon_p wIconCreateBitMap( wPos_t w, wPos_t h, const char * bits, wDrawColor color )
+{
+ wIcon_p ip;
+ ip = (wIcon_p)malloc( sizeof *ip );
+ ip->gtkIconType = gtkIcon_bitmap;
+ ip->w = w;
+ ip->h = h;
+ ip->color = color;
+ ip->bits = bits;
+ return ip;
+}
+
+wIcon_p wIconCreatePixMap( char *pm[] )
+{
+ wIcon_p ip;
+ ip = (wIcon_p)malloc( sizeof *ip );
+ ip->gtkIconType = gtkIcon_pixmap;
+ ip->w = 0;
+ ip->h = 0;
+ ip->color = 0;
+ ip->bits = pm;
+ return ip;
+}
+
+
+void wIconSetColor( wIcon_p ip, wDrawColor color )
+{
+ ip->color = color;
+}
+
+void wConvertToCharSet( char * buffPtr, int buffMax )
+{
+}
+
+
+void wConvertFromCharSet( char * buffPtr, int buffMax )
+{
+}
+
+static dynArr_t conversionBuffer_da;
+#define convesionBuffer(N) DYNARR_N( char, conversionBuffer_da, N )
+
+char * gtkConvertInput( const char * inString )
+{
+#ifndef GTK1
+ const char * cp;
+ char * cq;
+ int extCharCnt, inCharCnt;
+
+ /* Already UTF-8 encoded? */
+ if (g_utf8_validate(inString, -1, NULL))
+ /* Yes, do not double-convert */
+ return (char*)inString;
+#ifdef VERBOSE
+ fprintf(stderr, "gtkConvertInput(%s): Invalid UTF-8, converting...\n", inString);
+#endif
+
+ for ( cp=inString, extCharCnt=0; *cp; cp++ ) {
+ if ( ((*cp)&0x80) != 0 )
+ extCharCnt++;
+ }
+ inCharCnt = cp-inString;
+ if ( extCharCnt == 0 )
+ return (char*)inString;
+ DYNARR_SET( char, conversionBuffer_da, inCharCnt+extCharCnt+1 );
+ for ( cp=inString, cq=(char*)conversionBuffer_da.ptr; *cp; cp++ ) {
+ if ( ((*cp)&0x80) != 0 ) {
+ *cq++ = 0xC0+(((*cp)&0xC0)>>6);
+ *cq++ = 0x80+((*cp)&0x3F);
+ } else {
+ *cq++ = *cp;
+ }
+ }
+ *cq = 0;
+ return (char*)conversionBuffer_da.ptr;
+#else
+ return (char*)inString;
+#endif
+}
+
+
+char * gtkConvertOutput( const char * inString )
+{
+#ifndef GTK1
+ const char * cp;
+ char * cq;
+ int extCharCnt, inCharCnt;
+ for ( cp=inString, extCharCnt=0; *cp; cp++ ) {
+ if ( ((*cp)&0xC0) == 0x80 )
+ extCharCnt++;
+ }
+ inCharCnt = cp-inString;
+ if ( extCharCnt == 0 )
+ return (char*)inString;
+ DYNARR_SET( char, conversionBuffer_da, inCharCnt+1 );
+ for ( cp=inString, cq=(char*)conversionBuffer_da.ptr; *cp; cp++ ) {
+ if ( ((*cp)&0x80) != 0 ) {
+ *cq++ = 0xC0+(((*cp)&0xC0)>>6);
+ *cq++ = 0x80+((*cp)&0x3F);
+ } else {
+ *cq++ = *cp;
+ }
+ }
+ *cq = 0;
+ return (char*)conversionBuffer_da.ptr;
+#else
+ return (char*)inString;
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+
+typedef struct accelData_t {
+ wAccelKey_e key;
+ int modifier;
+ wAccelKeyCallBack_p action;
+ void * data;
+ } accelData_t;
+static dynArr_t accelData_da;
+#define accelData(N) DYNARR_N( accelData_t, accelData_da, N )
+
+
+static guint accelKeyMap[] = {
+ 0, /* wAccelKey_None, */
+ GDK_Delete, /* wAccelKey_Del, */
+ GDK_Insert, /* wAccelKey_Ins, */
+ GDK_Home, /* wAccelKey_Home, */
+ GDK_End, /* wAccelKey_End, */
+ GDK_Page_Up, /* wAccelKey_Pgup, */
+ GDK_Page_Down, /* wAccelKey_Pgdn, */
+ GDK_Up, /* wAccelKey_Up, */
+ GDK_Down, /* wAccelKey_Down, */
+ GDK_Right, /* wAccelKey_Right, */
+ GDK_Left, /* wAccelKey_Left, */
+ GDK_BackSpace, /* wAccelKey_Back, */
+ GDK_F1, /* wAccelKey_F1, */
+ GDK_F2, /* wAccelKey_F2, */
+ GDK_F3, /* wAccelKey_F3, */
+ GDK_F4, /* wAccelKey_F4, */
+ GDK_F5, /* wAccelKey_F5, */
+ GDK_F6, /* wAccelKey_F6, */
+ GDK_F7, /* wAccelKey_F7, */
+ GDK_F8, /* wAccelKey_F8, */
+ GDK_F9, /* wAccelKey_F9, */
+ GDK_F10, /* wAccelKey_F10, */
+ GDK_F11, /* wAccelKey_F11, */
+ GDK_F12 /* wAccelKey_F12, */
+ };
+
+
+EXPORT void wAttachAccelKey(
+ wAccelKey_e key,
+ int modifier,
+ wAccelKeyCallBack_p action,
+ void * data )
+{
+ accelData_t * ad;
+ if ( key < 1 || key > wAccelKey_F12 ) {
+ fprintf( stderr, "wAttachAccelKey(%d) out of range\n", (int)key );
+ return;
+ }
+ DYNARR_APPEND( accelData_t, accelData_da, 10 );
+ ad = &accelData(accelData_da.cnt-1);
+ ad->key = key;
+ ad->modifier = modifier;
+ ad->action = action;
+ ad->data = data;
+}
+
+
+EXPORT struct accelData_t * gtkFindAccelKey(
+ GdkEventKey * event )
+{
+ accelData_t * ad;
+ int modifier = 0;
+ if ( ( event->state & GDK_SHIFT_MASK ) )
+ modifier |= WKEY_SHIFT;
+ if ( ( event->state & GDK_CONTROL_MASK ) )
+ modifier |= WKEY_CTRL;
+ if ( ( event->state & GDK_MOD1_MASK ) )
+ modifier |= WKEY_ALT;
+ for ( ad=&accelData(0); ad<&accelData(accelData_da.cnt); ad++ )
+ if ( event->keyval == accelKeyMap[ad->key] &&
+ modifier == ad->modifier )
+ return ad;
+ return NULL;
+}
+
+
+EXPORT wBool_t gtkHandleAccelKey(
+ GdkEventKey *event )
+{
+ accelData_t * ad = gtkFindAccelKey( event );
+ if ( ad ) {
+ ad->action( ad->key, ad->data );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Timer Functions
+ *
+ *****************************************************************************
+ */
+
+static wBool_t gtkPaused = FALSE;
+static int alarmTimer = 0;
+
+static gint doAlarm(
+ gpointer data )
+{
+ wAlarmCallBack_p func = (wAlarmCallBack_p)data;
+ if (alarmTimer)
+ gtk_timeout_remove( alarmTimer );
+ func();
+ alarmTimer = 0;
+ return 0;
+}
+
+
+EXPORT void wAlarm(
+ long count,
+ wAlarmCallBack_p func ) /* milliseconds */
+/*
+Alarm for <count> milliseconds.
+*/
+{
+ gtkPaused = TRUE;
+ if (alarmTimer)
+ gtk_timeout_remove( alarmTimer );
+ alarmTimer = gtk_timeout_add( count, doAlarm, (void *) (GtkFunction)func );
+}
+
+
+static wControl_p triggerControl = NULL;
+static setTriggerCallback_p triggerFunc = NULL;
+
+static void doTrigger( void )
+{
+ if (triggerControl && triggerFunc) {
+ triggerFunc( triggerControl );
+ triggerFunc = NULL;
+ triggerControl = NULL;
+ }
+}
+
+void gtkSetTrigger(
+ wControl_p b,
+ setTriggerCallback_p trigger )
+{
+ triggerControl = b;
+ triggerFunc = trigger;
+ wAlarm( 500, doTrigger );
+}
+
+
+EXPORT void wPause(
+ long count ) /* milliseconds */
+/*
+Pause for <count> milliseconds.
+*/
+{
+ struct timeval timeout;
+ sigset_t signal_mask;
+ sigset_t oldsignal_mask;
+
+ gdk_display_sync(gdk_display_get_default());
+
+ timeout.tv_sec = count/1000;
+ timeout.tv_usec = (count%1000)*1000;
+
+ sigemptyset( &signal_mask );
+ sigaddset( &signal_mask, SIGIO );
+ sigaddset( &signal_mask, SIGALRM );
+ sigprocmask( SIG_BLOCK, &signal_mask, &oldsignal_mask );
+
+ if (select( 0, NULL, NULL, NULL, &timeout ) == -1) {
+ perror("wPause:select");
+ }
+ sigprocmask( SIG_BLOCK, &oldsignal_mask, NULL );
+}
+
+
+unsigned long wGetTimer( void )
+{
+ struct timeval tv;
+ struct timezone tz;
+ int rc;
+ rc = gettimeofday( &tv, &tz );
+ return (tv.tv_sec-startTime.tv_sec+1) * 1000 + tv.tv_usec /1000;
+}
+
+
+
+/**
+ * Add control to circular list of synonymous controls. Synonymous controls are kept in sync by
+ * calling wControlLinkedActive for one member of the list
+ *
+ * \param b1 IN first control
+ * \param b2 IN second control
+ * \return none
+ */
+
+EXPORT 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 b IN control
+ * \param active IN state
+ * \return none
+ */
+
+
+EXPORT 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;
+ }
+}
+
+/*
+ *****************************************************************************
+ *
+ * Control Utilities
+ *
+ *****************************************************************************
+ */
+
+EXPORT void wControlShow(
+ wControl_p b, /* Control */
+ wBool_t show ) /* Command */
+/*
+Cause the control <b> to be displayed or hidden.
+Used to hide control (such as a list) while it is being updated.
+*/
+{
+ if ( b->type == B_LINES ) {
+ gtkLineShow( (wLine_p)b, show );
+ return;
+ }
+ if (b->widget == 0) abort();
+ if (show) {
+ gtk_widget_show( b->widget );
+ if (b->label)
+ gtk_widget_show( b->label );
+ } else {
+ gtk_widget_hide( b->widget );
+ if (b->label)
+ gtk_widget_hide( b->label );
+ }
+}
+
+EXPORT void wControlActive(
+ wControl_p b, /* Control */
+ int active ) /* Command */
+/*
+Cause the control <b> to be marked active or inactive.
+Inactive controls donot respond to actions.
+*/
+{
+ if (b->widget == 0) abort();
+ gtk_widget_set_sensitive( GTK_WIDGET(b->widget), active );
+}
+
+
+EXPORT wPos_t wLabelWidth(
+ const char * label ) /* Label */
+/*
+Returns the width of <label>.
+This is used for computing window layout.
+Typically the width to the longest label is computed and used as
+the X-position for <controls>.
+*/
+{
+ GtkWidget * widget;
+ GtkRequisition requisition;
+ widget = gtk_label_new( gtkConvertInput(label) );
+ gtk_widget_size_request( widget, &requisition );
+ gtk_widget_destroy( widget );
+ return requisition.width+8;
+}
+
+
+EXPORT wPos_t wControlGetWidth(
+ wControl_p b) /* Control */
+{
+ return b->w;
+}
+
+
+EXPORT wPos_t wControlGetHeight(
+ wControl_p b) /* Control */
+{
+ return b->h;
+}
+
+
+EXPORT wPos_t wControlGetPosX(
+ wControl_p b) /* Control */
+{
+ return b->realX;
+}
+
+
+EXPORT wPos_t wControlGetPosY(
+ wControl_p b) /* Control */
+{
+ return b->realY - FOUR - ((b->parent->option&F_MENUBAR)?MENUH:0);
+}
+
+
+EXPORT void wControlSetPos(
+ wControl_p b, /* Control */
+ wPos_t x, /* X-position */
+ wPos_t y ) /* Y-position */
+{
+ b->realX = x;
+ b->realY = y + FOUR + ((b->parent->option&F_MENUBAR)?MENUH:0);
+#ifndef GTK1
+ if (b->widget)
+ gtk_fixed_move( GTK_FIXED(b->parent->widget), b->widget, b->realX, b->realY );
+ if (b->label)
+ gtk_fixed_move( GTK_FIXED(b->parent->widget), b->label, b->realX-b->labelW, b->realY+LABEL_OFFSET );
+#else
+ if (b->widget)
+ gtk_widget_set_uposition( b->widget, b->realX, b->realY );
+ if (b->label)
+ gtk_widget_set_uposition( b->label, b->realX-b->labelW, b->realY+LABEL_OFFSET );
+#endif
+}
+
+
+EXPORT void wControlSetLabel(
+ wControl_p b,
+ const char * labelStr )
+{
+ GtkRequisition requisition;
+ if (b->label) {
+ gtk_label_set( GTK_LABEL(b->label), gtkConvertInput(labelStr) );
+ gtk_widget_size_request( b->label, &requisition );
+ b->labelW = requisition.width+8;
+#ifndef GTK1
+ gtk_fixed_move( GTK_FIXED(b->parent->widget), b->label, b->realX-b->labelW, b->realY+LABEL_OFFSET );
+#else
+ gtk_widget_set_uposition( b->label, b->realX-b->labelW, b->realY+LABEL_OFFSET );
+#endif
+ } else {
+ b->labelW = gtkAddLabel( b, labelStr );
+ }
+}
+
+EXPORT void wControlSetContext(
+ wControl_p b,
+ void * context )
+{
+ b->data = context;
+}
+
+
+EXPORT void wControlSetFocus(
+ wControl_p b )
+{
+}
+
+
+static int gtkControlHiliteWidth = 3;
+EXPORT void wControlHilite(
+ wControl_p b,
+ wBool_t hilite )
+{
+ int off = gtkControlHiliteWidth/2+1;
+ if ( b->parent->gc == NULL ) {
+ b->parent->gc = gdk_gc_new( b->parent->gtkwin->window );
+ gdk_gc_copy( b->parent->gc, b->parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+ b->parent->gc_linewidth = 0;
+ gdk_gc_set_line_attributes( b->parent->gc, b->parent->gc_linewidth, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ if ( b->widget == NULL )
+ return;
+ if ( ! GTK_WIDGET_VISIBLE( b->widget ) )
+ return;
+ if ( ! GTK_WIDGET_VISIBLE( b->parent->widget ) )
+ return;
+ gdk_gc_set_foreground( b->parent->gc, gtkGetColor( wDrawColorBlack, FALSE ) );
+ gdk_gc_set_function( b->parent->gc, GDK_XOR );
+ gdk_gc_set_line_attributes( b->parent->gc, gtkControlHiliteWidth, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ gdk_draw_line( b->parent->widget->window, b->parent->gc,
+ b->realX - gtkControlHiliteWidth,
+ b->realY - off,
+ b->realX + b->w + gtkControlHiliteWidth,
+ b->realY - off );
+ gdk_draw_line( b->parent->widget->window, b->parent->gc,
+ b->realX - gtkControlHiliteWidth,
+ b->realY + b->h + off - 1,
+ b->realX + b->w + gtkControlHiliteWidth,
+ b->realY + b->h + off - 1 );
+ gdk_draw_line( b->parent->widget->window, b->parent->gc,
+ b->realX - off,
+ b->realY,
+ b->realX - off,
+ b->realY + b->h );
+ gdk_draw_line( b->parent->widget->window, b->parent->gc,
+ b->realX + b->w + off - 1,
+ b->realY,
+ b->realX + b->w + off - 1,
+ b->realY + b->h );
+}
+
+/*
+ *******************************************************************************
+ *
+ * Main
+ *
+ *******************************************************************************
+ */
+
+#ifdef GTK
+static wBool_t wAbortOnErrors = FALSE;
+#endif
+
+int do_rgb_init = 1;
+
+int main( int argc, char *argv[] )
+{
+ wWin_p win;
+ wControl_p b;
+ const char *ld, *hp;
+ static char buff[BUFSIZ];
+
+ if ( getenv( "GTKLIB_NOLOCALE" ) == 0 )
+ setlocale( LC_ALL, "en_US" );
+ gtk_init( &argc, &argv );
+ gettimeofday( &startTime, NULL );
+
+ if ( getenv( "XVLIB_REVERSEICON" ) != 0 )
+ reverseIcon = !reverseIcon;
+
+ if ( do_rgb_init )
+ gdk_rgb_init(); /* before we try to draw */
+
+ if ((win=wMain( argc, argv )) == (wWin_p)0)
+ exit(1);
+
+ ld = wGetAppLibDir();
+ if (ld != NULL) {
+ sprintf( buff, "HELPPATH=/usr/lib/help:%s:", ld );
+ if ( (hp = getenv("HELPPATH")) != NULL )
+ strcat( buff, hp );
+ putenv( buff );
+ }
+
+ if (!win->shown)
+ wWinShow( win, TRUE );
+ for (b=win->first; b != NULL; b = b->next) {
+ if (b->repaintProc)
+ b->repaintProc( b );
+ }
+ gtk_main();
+ exit(0);
+}
diff --git a/app/wlib/gtklib/gtksimple.c b/app/wlib/gtklib/gtksimple.c
new file mode 100644
index 0000000..244c0a3
--- /dev/null
+++ b/app/wlib/gtklib/gtksimple.c
@@ -0,0 +1,366 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtksimple.c,v 1.6 2009-09-25 05:38:15 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "gtkint.h"
+
+static int windowxxx = 0;
+/*
+ *****************************************************************************
+ *
+ * Message Boxes
+ *
+ *****************************************************************************
+ */
+
+struct wMessage_t {
+ WOBJ_COMMON
+ GtkWidget * labelWidget;
+ const char * message;
+ wPos_t labelWidth;
+ };
+
+EXPORT void wMessageSetValue(
+ wMessage_p b,
+ const char * arg )
+{
+ if (b->widget == 0) abort();
+ gtk_label_set( GTK_LABEL( b->labelWidget ), gtkConvertInput(arg) );
+}
+
+
+EXPORT void wMessageSetWidth(
+ wMessage_p b,
+ wPos_t width )
+{
+ b->labelWidth = width;
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, width, -1 );
+#else
+ gtk_widget_set_usize( b->widget, width, -1 );
+#endif
+}
+
+
+EXPORT wPos_t wMessageGetHeight(
+ long flags )
+{
+ return 14;
+}
+
+/**
+ * Create a window for a simple text.
+ *
+ * \param IN parent Handle of parent window
+ * \param IN x position in x direction
+ * \param IN y position in y direction
+ * \param IN labelStr ???
+ * \param IN width horizontal size of window
+ * \param IN message message to display ( null terminated )
+ * \param IN flags display options
+ * \return handle for created window
+ */
+
+EXPORT wMessage_p wMessageCreateEx(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * labelStr,
+ wPos_t width,
+ const char *message,
+ long flags )
+{
+ wMessage_p b;
+ GtkRequisition requisition;
+ PangoFontDescription *fontDesc;
+ int fontSize;
+
+ b = (wMessage_p)gtkAlloc( parent, B_MESSAGE, x, y, NULL, sizeof *b, NULL );
+ gtkComputePos( (wControl_p)b );
+ b->message = message;
+ b->labelWidth = width;
+
+ b->labelWidget = gtk_label_new( message?gtkConvertInput(message):"" );
+
+ /* do we need to set a special font? */
+ if( wMessageSetFont( flags )) {
+ /* get the current font descriptor */
+ fontDesc = (b->labelWidget)->style->font_desc;
+
+ /* get the current font size */
+ fontSize = PANGO_PIXELS(pango_font_description_get_size( fontDesc ));
+
+ /* calculate the new font size */
+ if( flags & BM_LARGE ) {
+ pango_font_description_set_size( fontDesc, fontSize * 1.4 * PANGO_SCALE );
+ } else {
+ pango_font_description_set_size( fontDesc, fontSize * 0.7 * PANGO_SCALE );
+ }
+
+ /* set the new font size */
+ gtk_widget_modify_font( (GtkWidget *)b->labelWidget, fontDesc );
+ }
+
+ b->widget = gtk_fixed_new();
+ gtk_widget_size_request( GTK_WIDGET(b->labelWidget), &requisition );
+ gtk_container_add( GTK_CONTAINER(b->widget), b->labelWidget );
+
+ gtk_widget_set_size_request( b->widget, width?width:requisition.width, requisition.height );
+ gtkControlGetSize( (wControl_p)b );
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+
+ gtk_widget_show( b->widget );
+ gtk_widget_show( b->labelWidget );
+ gtkAddButton( (wControl_p)b );
+
+ /* Reset font size to normal */
+ if( wMessageSetFont( flags )) {
+ if( flags & BM_LARGE ) {
+ pango_font_description_set_size(fontDesc, fontSize * PANGO_SCALE);
+ } else {
+ pango_font_description_set_size(fontDesc, fontSize * PANGO_SCALE);
+ }
+ }
+ return b;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Lines
+ *
+ *****************************************************************************
+ */
+
+struct wLine_t {
+ WOBJ_COMMON
+ wBool_t visible;
+ int count;
+ wLines_t * lines;
+ };
+
+static void linesRepaint( wControl_p b )
+{
+ wLine_p bl = (wLine_p)(b);
+ int i;
+ wWin_p win = (wWin_p)(bl->parent);
+ GdkDrawable * window;
+ GdkColor *black;
+
+ if (!bl->visible)
+ return;
+if (windowxxx)
+ window = win->gtkwin->window;
+else
+ window = win->widget->window;
+
+ /* get the GC attached to the panel in main() */
+ black = gtkGetColor( wDrawColorBlack, TRUE );
+ gdk_gc_set_foreground( win->gc, black );
+ gdk_gc_set_function( win->gc, GDK_COPY );
+ for (i=0; i<bl->count; i++) {
+ if (win->gc_linewidth != bl->lines[i].width) {
+ win->gc_linewidth = bl->lines[i].width;
+ gdk_gc_set_line_attributes( win->gc, win->gc_linewidth, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ gdk_draw_line( window, win->gc,
+ bl->lines[i].x0, bl->lines[i].y0,
+ bl->lines[i].x1, bl->lines[i].y1 );
+ }
+}
+
+
+void gtkLineShow(
+ wLine_p bl,
+ wBool_t visible )
+{
+ bl->visible = visible;
+}
+
+
+wLine_p wLineCreate(
+ wWin_p parent,
+ const char * labelStr,
+ int count,
+ wLines_t * lines )
+{
+ wLine_p b;
+ int i;
+ b = (wLine_p)gtkAlloc( parent, B_LINES, 0, 0, labelStr, sizeof *b, NULL );
+ if (parent->gc == NULL) {
+ parent->gc = gdk_gc_new( parent->gtkwin->window );
+ gdk_gc_copy( parent->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+ parent->gc_linewidth = 0;
+ gdk_gc_set_line_attributes( parent->gc, parent->gc_linewidth, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ b->visible = TRUE;
+ b->count = count;
+ b->lines = lines;
+
+ b->w = b->h = 0;
+ for ( i=0; i<count; i++ ) {
+ if (lines[i].x0 > b->w)
+ b->w = lines[i].x0;
+ if (lines[i].y0 > b->h)
+ b->h = lines[i].y0;
+ if (lines[i].x1 > b->w)
+ b->w = lines[i].x1;
+ if (lines[i].y1 > b->h)
+ b->h = lines[i].y1;
+ }
+ b->repaintProc = linesRepaint;
+ gtkAddButton( (wControl_p)b );
+ b->widget = 0;
+ return b;
+}
+
+
+/*
+ *****************************************************************************
+ *
+ * Boxes
+ *
+ *****************************************************************************
+ */
+
+struct wBox_t {
+ WOBJ_COMMON
+ wBoxType_e boxTyp;
+ };
+
+#define B (1)
+#define W (2)
+#define SETCOLOR( S, N ) \
+ if ( lastColor != colors[style][S][N] ) { \
+ lastColor = colors[style][S][N]; \
+ gdk_gc_set_foreground( win->gc, (lastColor==B)?black:white ); \
+ }
+
+EXPORT void wBoxSetSize(
+ wBox_p b, /* */
+ wPos_t w, /* */
+ wPos_t h ) /* */
+{
+ b->w = w;
+ b->h = h;
+}
+
+
+EXPORT void gtkDrawBox(
+ wWin_p win,
+ wBoxType_e style,
+ wPos_t x,
+ wPos_t y,
+ wPos_t w,
+ wPos_t h )
+{
+ wPos_t x0, y0, x1, y1;
+ char lastColor;
+ GdkColor *white;
+ GdkColor *black;
+ GdkDrawable * window;
+ 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} } };
+
+if (windowxxx)
+ window = win->gtkwin->window;
+else
+ window = win->widget->window;
+ white = gtkGetColor( wDrawColorWhite, TRUE );
+ black = gtkGetColor( wDrawColorBlack, TRUE );
+ win->gc_linewidth = 0;
+ gdk_gc_set_line_attributes( win->gc, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ gdk_gc_set_function( win->gc, GDK_COPY );
+ x0 = x;
+ x1 = x+w;
+ y0 = y;
+ y1 = y+h;
+ lastColor = colors[style][0][0];
+ gdk_gc_set_foreground( win->gc, (lastColor==B)?black:white );
+ gdk_draw_line( window, win->gc, x0, y0, x0, y1 );
+ SETCOLOR( 1, 0 );
+ gdk_draw_line( window, win->gc, x0+1, y0, x1, y0 );
+ SETCOLOR( 2, 0 );
+ gdk_draw_line( window, win->gc, x1, y1, x0+1, y1 );
+ SETCOLOR( 3, 0 );
+ gdk_draw_line( window, win->gc, x1, y1-1, x1, y0+1 );
+ if (style < wBoxThickB)
+ return;
+ x0++; y0++; x1--; y1--;
+ SETCOLOR( 0, 1 );
+ gdk_draw_line( window, win->gc, x0, y0, x0, y1 );
+ SETCOLOR( 1, 1 );
+ gdk_draw_line( window, win->gc, x0+1, y0, x1, y0 );
+ SETCOLOR( 2, 1 );
+ gdk_draw_line( window, win->gc, x1, y1, x0+1, y1 );
+ SETCOLOR( 3, 1 );
+ gdk_draw_line( window, win->gc, x1, y1-1, x1, y0+1 );
+ gdk_gc_set_foreground( win->gc, black );
+}
+
+
+static void boxRepaint( wControl_p b )
+{
+ wBox_p bb = (wBox_p)(b);
+ wWin_p win = bb->parent;
+
+ gtkDrawBox( win, bb->boxTyp, bb->realX, bb->realY, bb->w, bb->h );
+}
+
+
+wBox_p wBoxCreate(
+ wWin_p parent,
+ wPos_t bx,
+ wPos_t by,
+ const char * labelStr,
+ wBoxType_e boxTyp,
+ wPos_t bw,
+ wPos_t bh )
+{
+ wBox_p b;
+ b = (wBox_p)gtkAlloc( parent, B_BOX, bx, by, labelStr, sizeof *b, NULL );
+ gtkComputePos( (wControl_p)b );
+ b->boxTyp = boxTyp;
+ b->w = bw;
+ b->h = bh;
+ if (parent->gc == NULL) {
+ parent->gc = gdk_gc_new( parent->gtkwin->window );
+ gdk_gc_copy( parent->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );
+ parent->gc_linewidth = 0;
+ gdk_gc_set_line_attributes( parent->gc, parent->gc_linewidth, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );
+ }
+ b->repaintProc = boxRepaint;
+ gtkAddButton( (wControl_p)b );
+ return b;
+}
+
diff --git a/app/wlib/gtklib/gtksingle.c b/app/wlib/gtklib/gtksingle.c
new file mode 100644
index 0000000..d106e17
--- /dev/null
+++ b/app/wlib/gtklib/gtksingle.c
@@ -0,0 +1,645 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtksingle.c,v 1.2 2009-05-15 18:54:20 m_fischer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <gtk/gtk.h>
+
+#include "gtkint.h"
+
+/*
+ *****************************************************************************
+ *
+ * Text Boxes
+ *
+ *****************************************************************************
+ */
+
+struct wString_t {
+ WOBJ_COMMON
+ char * valueP;
+ wIndex_t valueL;
+ wStringCallBack_p action;
+ wBool_t busy;
+ };
+
+void wStringSetValue(
+ wString_p b,
+ const char * arg )
+{
+ wBool_t busy;
+ if (b->widget == 0) abort();
+ busy = b->busy;
+ b->busy = TRUE;
+ gtk_entry_set_text( GTK_ENTRY(b->widget), arg );
+ b->busy = busy;
+}
+
+
+void wStringSetWidth(
+ wString_p b,
+ wPos_t w )
+{
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, w, -1 );
+#else
+ gtk_widget_set_usize( b->widget, w, -1 );
+#endif
+ b->w = w;
+}
+
+
+const char * wStringGetValue(
+ wString_p b )
+{
+ if (b->widget == 0) abort();
+ return gtk_entry_get_text( GTK_ENTRY(b->widget) );
+}
+
+
+static void triggerString(
+ wControl_p b )
+{
+ wString_p bs = (wString_p)b;
+ const char * s;
+
+ if (b == 0)
+ return;
+ if (bs->widget == 0) abort();
+ s = gtk_entry_get_text( GTK_ENTRY(bs->widget) );
+ if (debugWindow >= 2) printf("%s text = %s\n", bs->labelStr?bs->labelStr:"No label", s );
+ if (s == NULL)
+ return;
+ if (debugWindow >= 2) printf("triggerString( %s )\n", s );
+ if (bs->action) {
+ bs->busy = TRUE;
+ bs->action( s, bs->data );
+ bs->busy = FALSE;
+ }
+ gtkSetTrigger( NULL, NULL );
+ return;
+}
+
+
+static void stringActivated(
+ GtkEntry * widget,
+ wString_p b )
+{
+ const char * s;
+ if (b == 0)
+ return;
+ s = wStringGetValue(b);
+
+ if (debugWindow >= 2) printf("%s text = %s\n", b->labelStr?b->labelStr:"No label", s );
+ if (b->valueP)
+ strcpy( b->valueP, s );
+ if (b->action) {
+ b->busy = TRUE;
+ b->action( s, b->data );
+ b->busy = FALSE;
+ }
+}
+
+static void stringChanged(
+ GtkEntry * widget,
+ wString_p b )
+{
+ const char *new_value;
+ if (b == 0)
+ return;
+ if (b->busy)
+ return;
+ new_value = wStringGetValue(b);
+ if (b->valueP != NULL)
+ strcpy( b->valueP, new_value );
+ if (b->action)
+ gtkSetTrigger( (wControl_p)b, triggerString );
+ return;
+}
+
+wString_p wStringCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ long option,
+ wPos_t width,
+ char *valueP,
+ wIndex_t valueL,
+ wStringCallBack_p action,
+ void *data )
+{
+ wString_p b;
+
+ b = (wString_p)gtkAlloc( parent, B_TEXT, x, y, labelStr, sizeof *b, data );
+ b->valueP = valueP;
+ b->action = action;
+ b->option = option;
+ b->valueL = valueL;
+ gtkComputePos( (wControl_p)b );
+
+ if (valueL) {
+ b->widget = (GtkWidget*)gtk_entry_new_with_max_length( valueL );
+ } else {
+ b->widget = (GtkWidget*)gtk_entry_new();
+ }
+ if (b->widget == 0) abort();
+
+#ifndef GTK1
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), b->widget );
+ gtk_widget_set_uposition( b->widget, b->realX, b->realY );
+#endif
+ if ( width )
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, width, -1 );
+#else
+ gtk_widget_set_usize( b->widget, width, -1 );
+#endif
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ /*b->w += 4;*/
+ /*b->h += 4;*/
+ if (b->valueP)
+ wStringSetValue( b, b->valueP );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ gtkAddHelpString( b->widget, helpStr );
+ gtk_signal_connect( GTK_OBJECT(b->widget), "changed", GTK_SIGNAL_FUNC(stringChanged), b );
+ gtk_signal_connect( GTK_OBJECT(b->widget), "activate", GTK_SIGNAL_FUNC(stringActivated), b );
+ if (option & BO_READONLY)
+ gtk_entry_set_editable( GTK_ENTRY(b->widget), FALSE );
+ return b;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Floating Point Value Boxes
+ *
+ *****************************************************************************
+ */
+
+
+struct wFloat_t {
+ WOBJ_COMMON
+ double low, high;
+ double oldValue;
+ double * valueP;
+ wFloatCallBack_p action;
+ wBool_t busy;
+ };
+
+
+void wFloatSetValue(
+ wFloat_p b,
+ double arg )
+{
+ char message[80];
+ if (b->widget == 0) abort();
+ sprintf( message, "%0.3f", arg );
+ if (!b->busy) {
+ b->busy = TRUE;
+ gtk_entry_set_text( GTK_ENTRY(b->widget), message );
+ b->busy = FALSE;
+ }
+ if (b->valueP)
+ *b->valueP = arg;
+}
+
+
+double wFloatGetValue(
+ wFloat_p b )
+{
+ double ret;
+ const char * cp;
+ if (b->widget == 0) abort();
+ cp = gtk_entry_get_text( GTK_ENTRY(b->widget) );
+ ret = atof( cp );
+ return ret;
+}
+
+
+static void triggerFloat(
+ wControl_p b )
+{
+ wFloat_p bf = (wFloat_p)b;
+ const char * s;
+ char * cp;
+ double v;
+
+ if (b == 0)
+ return;
+ if (bf->widget == 0) abort();
+ s = gtk_entry_get_text( GTK_ENTRY(bf->widget) );
+ if (debugWindow >= 2) printf("%s text = %s\n", bf->labelStr?bf->labelStr:"No label", s );
+ if (s == NULL)
+ return;
+ v = strtod( s, &cp );
+ if (*cp!=0 || v < bf->low || v > bf->high)
+ return;
+ /*if (bf->oldValue == v)
+ return;*/
+ if (debugWindow >= 2) printf("triggerFloat( %0.3f )\n", v );
+ bf->oldValue = v;
+ if (bf->valueP)
+ *bf->valueP = v;
+ if (bf->action) {
+ bf->busy = TRUE;
+ bf->action( v, bf->data );
+ bf->busy = FALSE;
+ }
+ gtkSetTrigger( NULL, NULL );
+ return;
+}
+
+
+static void floatActivated(
+ GtkEntry *widget,
+ wFloat_p b )
+{
+ const char * s;
+ char * cp;
+ double v;
+ char val_s[80];
+
+ if (b == 0)
+ return;
+ if (b->widget == 0) abort();
+ s = gtk_entry_get_text( GTK_ENTRY(b->widget) );
+ if (debugWindow >= 2) printf("%s text = %s\n", b->labelStr?b->labelStr:"No label", s );
+ if (s != NULL) {
+ v = strtod( s, &cp );
+ if (*cp != '\n' && *cp != '\0') {
+ wNoticeEx( NT_ERROR, "The value you have entered is not a valid number\nPlease try again", "Ok", NULL );
+ } else if (v < b->low || v > b->high) {
+ sprintf( val_s, "Please enter a value between %0.3f and %0.3f", b->low, b->high );
+ wNoticeEx( NT_ERROR, val_s, "Ok", NULL );
+ } else {
+ if (debugWindow >= 2) printf("floatActivated( %0.3f )\n", v );
+ b->oldValue = v;
+ if (b->valueP)
+ *b->valueP = v;
+ if (b->action) {
+ gtkSetTrigger( NULL, NULL );
+ b->busy = TRUE;
+ b->action( v, b->data );
+ b->busy = FALSE;
+ }
+ return;
+ }
+ sprintf( val_s, "%0.3f", b->oldValue);
+ b->busy = TRUE;
+ gtk_entry_set_text( GTK_ENTRY(b->widget), val_s );
+ b->busy = FALSE;
+ }
+ return;
+}
+
+static void floatChanged(
+ GtkEntry *widget,
+ wFloat_p b )
+{
+ const char * s;
+ char * cp;
+ double v;
+
+ if (b == 0)
+ return;
+ if (b->widget == 0) abort();
+ if (b->busy)
+ return;
+ s = gtk_entry_get_text( GTK_ENTRY(b->widget) );
+ if (s == NULL)
+ return;
+ if (debugWindow >= 2) printf("%s text = %s\n", b->labelStr?b->labelStr:"No label", s );
+ if ( s[0] == '\0' ||
+ strcmp( s, "-" ) == 0 ||
+ strcmp( s, "." ) == 0 ) {
+ v = 0;
+ } else {
+ v = strtod( s, &cp );
+ if (*cp != '\0'
+#ifdef LATER
+ || v < b->low || v > b->high
+#endif
+ ) {
+ wBeep();
+ wFloatSetValue( b, b->oldValue );
+ return;
+ }
+ }
+ b->oldValue = v;
+ if (b->valueP != NULL) {
+ *b->valueP = v;
+ }
+ if (b->action)
+ gtkSetTrigger( (wControl_p)b, triggerFloat );
+ return;
+}
+
+wFloat_p wFloatCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ long option,
+ wPos_t width,
+ double low,
+ double high,
+ double *valueP,
+ wFloatCallBack_p action,
+ void *data )
+{
+ wFloat_p b;
+
+ b = (wFloat_p)gtkAlloc( parent, B_TEXT, x, y, labelStr, sizeof *b, data );
+ b->valueP = valueP;
+ b->action = action;
+ b->option = option;
+ b->low = low;
+ b->high = high;
+ gtkComputePos( (wControl_p)b );
+
+ b->widget = (GtkWidget*)gtk_entry_new_with_max_length( 20 );
+ if (b->widget == 0) abort();
+
+#ifndef GTK1
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), b->widget );
+ gtk_widget_set_uposition( b->widget, b->realX, b->realY );
+#endif
+ if ( width )
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, width, -1 );
+#else
+ gtk_widget_set_usize( b->widget, width, -1 );
+#endif
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ /*b->w += 4;*/
+ /*b->h += 4;*/
+ if (b->valueP)
+ wFloatSetValue( b, *b->valueP );
+ else
+ wFloatSetValue( b, b->low>0?b->low:0.0 );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ gtkAddHelpString( b->widget, helpStr );
+ gtk_signal_connect( GTK_OBJECT(b->widget), "changed", GTK_SIGNAL_FUNC(floatChanged), b );
+ gtk_signal_connect( GTK_OBJECT(b->widget), "activate", GTK_SIGNAL_FUNC(floatActivated), b );
+ if (option & BO_READONLY)
+ gtk_entry_set_editable( GTK_ENTRY(b->widget), FALSE );
+ return b;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Integer Value Boxes
+ *
+ *****************************************************************************
+ */
+
+
+struct wInteger_t {
+ WOBJ_COMMON
+ long low, high;
+ long oldValue;
+ long * valueP;
+ wIntegerCallBack_p action;
+ wBool_t busy;
+ };
+
+
+void wIntegerSetValue(
+ wInteger_p b,
+ long arg )
+{
+ char message[80];
+ if (b->widget == 0) abort();
+ sprintf( message, "%ld", arg );
+ if (!b->busy) {
+ b->busy = TRUE;
+ gtk_entry_set_text( GTK_ENTRY(b->widget), message );
+ b->busy = FALSE;
+ }
+ if (b->valueP)
+ *b->valueP = arg;
+}
+
+
+long wIntegerGetValue(
+ wInteger_p b )
+{
+ long ret;
+ const char * cp;
+ if (b->widget == 0) abort();
+ cp = gtk_entry_get_text( GTK_ENTRY(b->widget) );
+ ret = atol( cp );
+ return ret;
+}
+
+
+static void triggerInteger(
+ wControl_p b )
+{
+ wInteger_p bi = (wInteger_p)b;
+ const char * s;
+ char * cp;
+ long v;
+
+ if (b == 0)
+ return;
+ if (bi->widget == 0) abort();
+ s = gtk_entry_get_text( GTK_ENTRY(bi->widget) );
+ if (debugWindow >= 2) printf("%s text = %s\n", bi->labelStr?bi->labelStr:"No label", s );
+ if (s == NULL)
+ return;
+ v = strtol( s, &cp, 10 );
+ if (*cp!=0 || v < bi->low || v > bi->high)
+ return;
+ /*if (bi->oldValue == v)
+ return;*/
+ if (debugWindow >= 2) printf("triggerInteger( %ld )\n", v );
+ bi->oldValue = v;
+ if (bi->valueP)
+ *bi->valueP = v;
+ if (bi->action) {
+ bi->busy = TRUE;
+ bi->action( v, bi->data );
+ bi->busy = FALSE;
+ }
+ gtkSetTrigger( NULL, NULL );
+ return;
+}
+
+
+
+static void integerActivated(
+ GtkEntry *widget,
+ wInteger_p b )
+{
+ const char * s;
+ char * cp;
+ long v;
+ char val_s[80];
+
+ if (b == 0)
+ return;
+ if (b->widget == 0) abort();
+ s = gtk_entry_get_text( GTK_ENTRY(b->widget) );
+ if (debugWindow >= 2) printf("%s text = %s\n", b->labelStr?b->labelStr:"No label", s );
+ if (s != NULL) {
+ v = strtod( s, &cp );
+ if (*cp != '\n' && *cp != '\0') {
+ wNoticeEx( NT_ERROR, "The value you have entered is not a valid number\nPlease try again", "Ok", NULL );
+ } else if (v < b->low || v > b->high) {
+ sprintf( val_s, "Please enter a value between %ld and %ld", b->low, b->high );
+ wNoticeEx( NT_ERROR, val_s, "Ok", NULL );
+ } else {
+ if (debugWindow >= 2) printf("integerActivated( %ld )\n", v );
+ b->oldValue = v;
+ if (b->valueP)
+ *b->valueP = v;
+ if (b->action) {
+ gtkSetTrigger( NULL, NULL );
+ b->busy = TRUE;
+ b->action( v, b->data );
+ b->busy = FALSE;
+ }
+ return;
+ }
+ sprintf( val_s, "%ld", b->oldValue);
+ b->busy = TRUE;
+ gtk_entry_set_text( GTK_ENTRY(b->widget), val_s );
+ b->busy = FALSE;
+ }
+ return;
+}
+
+static void integerChanged(
+ GtkEntry *widget,
+ wInteger_p b )
+{
+ const char * s;
+ char * cp;
+ long v;
+
+ if (b == 0)
+ return;
+ if (b->widget == 0) abort();
+ if (b->busy)
+ return;
+ s = gtk_entry_get_text( GTK_ENTRY(b->widget) );
+ if (s == NULL)
+ return;
+ if (debugWindow >= 2) printf("%s text = %s\n", b->labelStr?b->labelStr:"No label", s );
+ if ( s[0] == '\0' ||
+ strcmp( s, "-" ) == 0 ) {
+ v = 0;
+ } else {
+ v = strtol( s, &cp, 10 );
+ if (*cp != '\0'
+#ifdef LATER
+ || v < b->low || v > b->high
+#endif
+ ) {
+ wBeep();
+ wIntegerSetValue( b, b->oldValue );
+ return;
+ }
+ }
+ b->oldValue = v;
+ if (b->valueP != NULL) {
+ *b->valueP = v;
+ }
+ if (b->action)
+ gtkSetTrigger( (wControl_p)b, triggerInteger );
+ return;
+}
+
+wInteger_p wIntegerCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ long option,
+ wPos_t width,
+ long low,
+ long high,
+ long *valueP,
+ wIntegerCallBack_p action,
+ void *data )
+{
+ wInteger_p b;
+
+ b = (wInteger_p)gtkAlloc( parent, B_TEXT, x, y, labelStr, sizeof *b, data );
+ b->valueP = valueP;
+ b->action = action;
+ b->option = option;
+ b->low = low;
+ b->high = high;
+ gtkComputePos( (wControl_p)b );
+
+ b->widget = (GtkWidget*)gtk_entry_new_with_max_length( 20 );
+ if (b->widget == 0) abort();
+
+#ifndef GTK1
+ gtk_fixed_put( GTK_FIXED(parent->widget), b->widget, b->realX, b->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), b->widget );
+ gtk_widget_set_uposition( b->widget, b->realX, b->realY );
+#endif
+ if ( width )
+#ifndef GTK1
+ gtk_widget_set_size_request( b->widget, width, -1 );
+#else
+ gtk_widget_set_usize( b->widget, width, -1 );
+#endif
+ gtkControlGetSize( (wControl_p)b );
+ if (labelStr)
+ b->labelW = gtkAddLabel( (wControl_p)b, labelStr );
+ /*b->w += 4;*/
+ /*b->h += 4;*/
+ if (b->valueP)
+ wIntegerSetValue( b, *b->valueP );
+ else
+ wIntegerSetValue( b, b->low>0?b->low:0.0 );
+ gtk_widget_show( b->widget );
+ gtkAddButton( (wControl_p)b );
+ gtkAddHelpString( b->widget, helpStr );
+ gtk_signal_connect( GTK_OBJECT(b->widget), "changed", GTK_SIGNAL_FUNC(integerChanged), b );
+ gtk_signal_connect( GTK_OBJECT(b->widget), "activate", GTK_SIGNAL_FUNC(integerActivated), b );
+ if (option & BO_READONLY)
+ gtk_entry_set_editable( GTK_ENTRY(b->widget), FALSE );
+ return b;
+}
diff --git a/app/wlib/gtklib/gtksplash.c b/app/wlib/gtklib/gtksplash.c
new file mode 100644
index 0000000..0f49774
--- /dev/null
+++ b/app/wlib/gtklib/gtksplash.c
@@ -0,0 +1,142 @@
+/** \file gtksplash.c
+ * Handling of the Splash Window functions
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtksplash.c,v 1.5 2009-05-31 14:48:58 m_fischer Exp $
+ */
+
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "gtkint.h"
+
+#define LOGOFILENAME "logo.bmp"
+
+static GtkWidget *window; /** splash window handle */
+static GtkWidget *message; /** window handle for progress message */
+
+/**
+ * Create the splash window shown during startup. The function loads the logo
+ * bitmap and displays the program name and version as passed.
+ *
+ * \param IN appName the product name to be shown
+ * \param IN appVer the product version to be shown
+ * \return TRUE if window was created, FALSE if an error occured
+ */
+
+int
+wCreateSplash( char *appName, char *appVer )
+{
+ GtkWidget *vbox;
+ GtkWidget *image;
+ GtkWidget *label;
+ char *temp;
+ char logoPath[BUFSIZ];
+
+ /* create the basic window */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_decorated( GTK_WINDOW (window), FALSE );
+ gtk_window_set_title (GTK_WINDOW (window), appName);
+ gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
+ gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+ gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
+#if GTK_MINOR_VERSION > 5
+ gtk_window_set_focus_on_map (GTK_WINDOW (window), FALSE);
+#endif
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ /* add the logo image to the top of the splash window */
+ sprintf( logoPath, "%s/" LOGOFILENAME, wGetAppLibDir());
+ image = gtk_image_new_from_file ( logoPath );
+ gtk_widget_show (image);
+ gtk_box_pack_start (GTK_BOX (vbox), image, TRUE, TRUE, 0);
+ gtk_misc_set_alignment (GTK_MISC (image), 0, 0);
+
+ /* put the product name into the window */
+
+ temp = malloc( strlen( appName ) + strlen( appVer ) + 2 );
+ if( !temp )
+ return( FALSE );
+
+ sprintf( temp, "%s %s", appName, appVer );
+
+ label = gtk_label_new ( temp );
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
+ gtk_label_set_selectable (GTK_LABEL (label), FALSE);
+ gtk_misc_set_padding (GTK_MISC (label), 6, 2);
+
+ free( temp );
+
+ label = gtk_label_new ("Application is starting...");
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_label_set_line_wrap (GTK_LABEL (label), FALSE);
+ gtk_misc_set_padding (GTK_MISC (label), 6, 2);
+#if GTK_MINOR_VERSION > 5
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_START);
+#endif
+ message = label;
+
+ gtk_widget_show( window );
+
+ return( TRUE );
+}
+
+/**
+ * Update the progress message inside the splash window
+ * msg text message to display
+ * return nonzero if ok
+ */
+
+int
+wSetSplashInfo( char *msg )
+{
+ if( msg ) {
+ gtk_label_set_text( (GtkLabel *)message, msg );
+ wFlush();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Destroy the splash window.
+ *
+ */
+
+void
+wDestroySplash( void )
+{
+ /* kill window */
+ gtk_widget_destroy( window );
+ return;
+}
diff --git a/app/wlib/gtklib/gtktext.c b/app/wlib/gtklib/gtktext.c
new file mode 100644
index 0000000..8da31d3
--- /dev/null
+++ b/app/wlib/gtklib/gtktext.c
@@ -0,0 +1,524 @@
+/** \file gtktext.c
+ * Multi line text entry
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define GTK_ENABLE_BROKEN
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gtkint.h"
+
+/*
+ * Disable USE_TEXTVIEW to use the deprecated gtk_text
+ */
+#define USE_TEXTVIEW
+
+/*
+ *****************************************************************************
+ *
+ * Multi-line Text Boxes
+ *
+ *****************************************************************************
+ */
+
+struct wText_t {
+ WOBJ_COMMON
+ wPos_t width, height;
+ int changed;
+ GtkWidget * text;
+ GtkWidget * vscroll;
+ };
+
+EXPORT void wTextClear(
+ wText_p bt )
+{
+#ifdef USE_TEXTVIEW
+ GtkTextBuffer * tb;
+#endif
+ if (bt->text == 0) abort();
+#ifdef USE_TEXTVIEW
+ tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(bt->text) );
+ gtk_text_buffer_set_text( tb, "", -1 );
+ if (bt->option & BO_READONLY)
+ gtk_text_view_set_editable( GTK_TEXT_VIEW(bt->text), FALSE );
+#else
+ gtk_text_set_point( GTK_TEXT(bt->text), 0 );
+ gtk_text_forward_delete( GTK_TEXT(bt->text), gtk_text_get_length( GTK_TEXT(bt->text) ) );
+ if (bt->option & BO_READONLY)
+ gtk_text_set_editable( GTK_TEXT(bt->text), FALSE );
+#endif
+ bt->changed = FALSE;
+}
+
+/**
+ * Add text to a multiline text field. Font is selected as requested.
+ * Bold is supported if the flags BT_BOLD is set as flags for the entry
+ * field. For bold, pango text markup is used
+ *
+ *
+ * \param bt IN the text field
+ * \param text IN text to add
+ */
+
+EXPORT void wTextAppend(
+ wText_p bt,
+ const char * text )
+{
+#ifdef USE_TEXTVIEW
+ GtkTextBuffer * tb;
+ GtkTextIter ti1, ti2;
+// PangoFontDescription *pfd;
+#else
+ static GdkFont * fixedRegularFont = NULL;
+ static GdkFont * fixedBoldFont = NULL;
+ static GdkFont * variableRegularFont = NULL;
+ static GdkFont * variableBoldFont = NULL;
+ GdkFont * regularFont = NULL;
+ GdkFont * boldFont = NULL;
+#endif
+ wBool_t doBold;
+ char * cp;
+ int len;
+
+ if (bt->text == 0) abort();
+#ifdef USE_TEXTVIEW
+ tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(bt->text) );
+ //if ((bt->option&BT_FIXEDFONT)) {
+ ///* creating PangoFontDescription from string, specified in entry */
+ //pfd = pango_font_description_from_string("Monospace");
+ ///* setting label's font */
+ //gtk_widget_modify_font(GTK_WIDGET(tb), pfd);
+ ///* freeing PangoFontDescription, cause it has been copied by prev. call */
+ //pango_font_description_free(pfd);
+ //}
+#else
+ if ((bt->option&BT_FIXEDFONT)) {
+ if (fixedRegularFont==NULL)
+ fixedRegularFont = gdk_font_load( "-*-courier-medium-r-*-*-12-*-*-*-*-*-iso8859-*" );
+ if (fixedBoldFont==NULL)
+ fixedBoldFont = gdk_font_load( "-*-courier-bold-r-*-*-12-*-*-*-*-*-iso8859-*" );
+ regularFont = fixedRegularFont;
+ boldFont = fixedBoldFont;
+ } else {
+ if (variableRegularFont==NULL)
+ variableRegularFont = gdk_font_load( "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-*" );
+ if (variableBoldFont==NULL)
+ variableBoldFont = gdk_font_load( "-*-helvetica-bold-r-*-*-12-*-*-*-*-*-iso8859-*" );
+ regularFont = variableRegularFont;
+ boldFont = variableBoldFont;
+ }
+#endif
+ /*gtk_text_freeze( GTK_TEXT (bt->text) );*/
+ doBold = FALSE;
+ text = gtkConvertInput( text );
+ while ( text && *text ) {
+ if ( (bt->option & BT_DOBOLD) != 0 &&
+ ( cp = strchr( text, doBold?'>':'<' ) ) != NULL ) {
+ len = cp-text;
+ cp++;
+ } else {
+ len = -1;
+ cp = NULL;
+ }
+ if ( len != 0 ) {
+#ifdef USE_TEXTVIEW
+ gtk_text_buffer_get_bounds( tb, &ti1, &ti2 );
+ if ( !doBold )
+ gtk_text_buffer_insert( tb, &ti2, text, len );
+ else
+ gtk_text_buffer_insert_with_tags_by_name( tb, &ti2, text, len, "bold", NULL );
+#else
+ gtk_text_insert( GTK_TEXT(bt->text), doBold?boldFont:regularFont, &bt->text->style->black, NULL, text, len );
+#endif
+ }
+ text = cp;
+ doBold = !doBold;
+ }
+ /*gtk_text_set_point( GTK_TEXT(bt->text), gtk_text_get_length( GTK_TEXT(bt->text) )-1 );*/
+ /*gtk_text_thaw( GTK_TEXT (bt->text) );*/
+ bt->changed = FALSE;
+}
+
+EXPORT void gtkTextFreeze(
+ wText_p bt )
+{
+#ifdef USE_TEXTVIEW
+ gtk_text_view_set_editable( GTK_TEXT_VIEW(bt->text), FALSE );
+#else
+ gtk_text_freeze( GTK_TEXT (bt->text) );
+#endif
+}
+
+EXPORT void gtkTextThaw(
+ wText_p bt )
+{
+#ifdef USE_TEXTVIEW
+ gtk_text_view_set_editable( GTK_TEXT_VIEW(bt->text), TRUE );
+#else
+ gtk_text_thaw( GTK_TEXT (bt->text) );
+#endif
+}
+
+EXPORT void wTextReadFile(
+ wText_p bt,
+ const char * fileName )
+{
+ FILE * f;
+ char buff[BUFSIZ+1];
+ if (fileName) {
+ f = fopen( fileName, "r" );
+ if (f == NULL) {
+ perror( fileName );
+ return;
+ }
+ while (fgets( buff, sizeof buff, f ) != NULL ) {
+ wTextAppend( bt, buff );
+ }
+ }
+}
+
+
+#ifdef USE_TEXTVIEW
+static char * gtkGetText(
+ wText_p bt )
+{
+ GtkTextBuffer * tb;
+ GtkTextIter ti1, ti2;
+ char * cp;
+ if (bt->text == 0) abort();
+ tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(bt->text) );
+ gtk_text_buffer_get_bounds( tb, &ti1, &ti2 );
+ cp = gtk_text_buffer_get_text( tb, &ti1, &ti2, FALSE );
+ cp = gtkConvertOutput( cp );
+ return cp;
+}
+#endif
+
+
+EXPORT wBool_t wTextSave(
+ wText_p bt,
+ const char * fileName )
+{
+#ifndef USE_TEXTVIEW
+ int siz, pos, cnt;
+#endif
+ FILE * f;
+ char * cp;
+
+ f = fopen( fileName, "w" );
+ if (f==NULL) {
+ wNoticeEx( NT_ERROR, fileName, "Ok", NULL );
+ return FALSE;
+ }
+#ifdef USE_TEXTVIEW
+ cp = gtkGetText( bt );
+ fwrite( cp, 1, strlen(cp), f );
+ free(cp);
+#else
+ siz = gtk_text_get_length( GTK_TEXT(bt->text) );
+ pos = 0;
+ cnt = BUFSIZ;
+ while (pos<siz) {
+ if (pos+cnt>siz)
+ cnt = siz-pos;
+ cp = gtk_editable_get_chars( GTK_EDITABLE(bt->text), pos, pos+cnt );
+ if (cp == NULL)
+ break;
+ fwrite( cp, 1, cnt, f );
+ free(cp);
+ pos += cnt;
+ }
+#endif
+ fclose(f);
+ return TRUE;
+}
+
+
+EXPORT wBool_t wTextPrint(
+ wText_p bt )
+{
+ wPrinterStream_p f;
+#ifndef USE_TEXTVIEW
+ int siz, pos, cnt;
+#endif
+ char * cp;
+
+ f = wPrinterOpen();
+ if (f==NULL) {
+ return FALSE;
+ }
+#ifdef USE_TEXTVIEW
+ cp = gtkGetText( bt );
+ wPrinterWrite( f, cp, strlen(cp) );
+ free(cp);
+
+#else
+ siz = gtk_text_get_length( GTK_TEXT(bt->text) );
+ pos = 0;
+ cnt = BUFSIZ;
+ while (pos<siz) {
+ if (pos+cnt>siz)
+ cnt = siz-pos;
+ cp = gtk_editable_get_chars( GTK_EDITABLE(bt->text), pos, pos+cnt );
+ if (cp == NULL)
+ break;
+ wPrinterWrite( f, cp, cnt );
+ free(cp);
+ pos += cnt;
+ }
+#endif
+ wPrinterClose(f);
+ return TRUE;
+}
+
+
+EXPORT int wTextGetSize(
+ wText_p bt )
+{
+#ifdef USE_TEXTVIEW
+ char * cp = gtkGetText( bt );
+ int len = strlen( cp );
+ free( cp );
+ return len;
+#else
+ return (int)gtk_text_get_length( GTK_TEXT(bt->text) );
+#endif
+}
+
+
+EXPORT void wTextGetText(
+ wText_p bt,
+ char * text,
+ int len )
+{
+ char * cp;
+#ifdef USE_TEXTVIEW
+ cp = gtkGetText(bt);
+ strncpy( text, cp, len );
+ free( cp );
+#else
+ cp = gtk_editable_get_chars( GTK_EDITABLE(bt->text), 0, len );
+ strncpy( text, cp, len );
+#endif
+}
+
+
+EXPORT void wTextSetReadonly (
+ wText_p bt,
+ wBool_t ro )
+{
+#ifdef USE_TEXTVIEW
+ gtk_text_view_set_editable( GTK_TEXT_VIEW(bt->text), !ro );
+#else
+ gtk_text_set_editable( GTK_TEXT(bt->text), !ro );
+#endif
+ if (ro) {
+ bt->option |= BO_READONLY;
+ } else {
+ bt->option &= ~BO_READONLY;
+ }
+}
+
+
+EXPORT wBool_t wTextGetModified(
+ wText_p bt )
+{
+ return bt->changed;
+}
+
+
+EXPORT void wTextSetSize(
+ wText_p bt,
+ wPos_t w,
+ wPos_t h )
+{
+#ifdef USE_TEXTVIEW
+ gtk_widget_set_size_request( bt->widget, w, h );
+// gtk_widget_set_size_request( bt->text, w-15, h );
+// gtk_widget_set_size_request( bt->vscroll, 15, h );
+#else
+ gtk_widget_set_usize( bt->widget, w, h );
+ gtk_widget_set_usize( bt->text, w-15, h );
+ gtk_widget_set_usize( bt->vscroll, 15, h );
+ gtk_widget_queue_resize( GTK_WIDGET(bt->widget) );
+ gtk_widget_queue_resize( GTK_WIDGET(bt->text) );
+ gtk_widget_queue_resize( GTK_WIDGET(bt->vscroll) );
+#endif
+ bt->w = w;
+ bt->h = h;
+}
+
+
+EXPORT void wTextComputeSize(
+ wText_p bt,
+ int rows,
+ int cols,
+ wPos_t *width,
+ wPos_t *height )
+{
+ *width = rows * 7;
+ *height = cols * 14;
+}
+
+
+EXPORT void wTextSetPosition(
+ wText_p bt,
+ int pos )
+{
+#ifdef USE_TEXTVIEW
+ /* TODO */
+#else
+ GTK_TEXT(bt->text)->first_line_start_index = pos;
+ gtk_text_set_word_wrap( GTK_TEXT(bt->text), TRUE );
+ gtk_text_set_point( GTK_TEXT(bt->text), pos );
+#endif
+}
+
+static void textChanged(
+ GtkWidget * widget,
+ wText_p bt )
+{
+ if (bt == 0)
+ return;
+ bt->changed = TRUE;
+}
+
+/**
+ * Create a multi line text entry widget. The created widget is
+ * configured as requested by the BT_* flags. This includes Monospaced
+ * font for BT_FIXEDFONT, readonly for BT_READONLY and a markup for
+ * bold when setup via BT_BOLD.
+ *
+ * \param parent IN parent window
+ * \param x,y IN position
+ * \param helpstr IN label for linking into help system
+ * \param labelStr IN label
+ * \param option IN widget options
+ * \param width, height IN size of widget
+ * \return handle for new widget
+ */
+
+EXPORT wText_p wTextCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ long option,
+ wPos_t width,
+ wPos_t height )
+{
+ wText_p bt;
+#ifdef USE_TEXTVIEW
+ GtkTextBuffer * tb;
+ PangoFontDescription *pfd;
+#else
+ GtkRequisition requisition;
+#endif
+ bt = gtkAlloc( parent, B_MULTITEXT, x, y, labelStr, sizeof *bt, NULL );
+ gtkComputePos( (wControl_p)bt );
+ bt->width = width;
+ bt->height = height;
+ bt->option = option;
+ gtkComputePos( (wControl_p)bt );
+
+#ifdef USE_TEXTVIEW
+ bt->widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (bt->widget),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ bt->text = gtk_text_view_new();
+ if (bt->text == 0) abort();
+ gtk_container_add (GTK_CONTAINER (bt->widget), bt->text);
+ tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(bt->text) );
+ gtk_text_buffer_create_tag( tb, "bold", "weight", PANGO_WEIGHT_BOLD, NULL);
+/* gtk_text_buffer_create_tag( tb, "italic", "style", PANGO_STYLE_ITALIC, NULL); */
+/* gtk_text_buffer_create_tag( tb, "bolditalic", "weight", PANGO_WEIGHT_BOLD, "style", PANGO_STYLE_ITALIC, NULL); */
+ if ((bt->option & BT_FIXEDFONT)) {
+ /* creating PangoFontDescription from string, specified in entry */
+ pfd = pango_font_description_from_string("Monospace");
+ /* setting label's font */
+ gtk_widget_modify_font(GTK_WIDGET(bt->text), pfd);
+ /* freeing PangoFontDescription, cause it has been copied by prev. call */
+ pango_font_description_free(pfd);
+ }
+ bt->vscroll = gtk_vscrollbar_new( GTK_TEXT_VIEW(bt->text)->vadjustment );
+ if (bt->vscroll == 0) abort();
+#else
+ bt->widget = gtk_hbox_new( FALSE, 0 );
+ bt->text = gtk_text_new( NULL, NULL );
+ if (bt->text == 0) abort();
+ gtk_box_pack_start( GTK_BOX(bt->widget), bt->text, FALSE, FALSE, 0 );
+ bt->vscroll = gtk_vscrollbar_new( GTK_TEXT(bt->text)->vadj );
+ if (bt->vscroll == 0) abort();
+ gtk_box_pack_start( GTK_BOX(bt->widget), bt->vscroll, FALSE, FALSE, 0 );
+#endif
+ if (option&BT_CHARUNITS) {
+ width *= 7;
+ height *= 14;
+ }
+ gtk_widget_show( bt->text );
+ gtk_widget_show( bt->vscroll );
+ gtk_widget_show( bt->widget );
+#ifdef USE_TEXTVIEW
+// gtk_widget_set_size_request( GTK_WIDGET(bt->text), width, height );
+// gtk_widget_set_size_request( GTK_WIDGET(bt->vscroll), -1, height );
+ gtk_widget_set_size_request( GTK_WIDGET(bt->widget), width+15/*requisition.width*/, height );
+#else
+ gtk_widget_set_usize( GTK_WIDGET(bt->text), width, height );
+ gtk_widget_set_usize( GTK_WIDGET(bt->vscroll), -1, height );
+ gtk_widget_size_request( GTK_WIDGET(bt->vscroll), &requisition );
+ gtk_widget_set_usize( GTK_WIDGET(bt->widget), width+15/*requisition.width*/, height );
+#endif
+ if (bt->option&BO_READONLY) {
+#ifdef USE_TEXTVIEW
+ gtk_text_view_set_editable( GTK_TEXT_VIEW(bt->text), FALSE );
+ gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(bt->text), FALSE);
+#else
+ gtk_text_set_editable( GTK_TEXT(bt->text), FALSE );
+#endif
+ }
+
+#ifdef USE_TEXTVIEW
+ gtk_fixed_put( GTK_FIXED(parent->widget), bt->widget, bt->realX, bt->realY );
+#else
+ gtk_container_add( GTK_CONTAINER(parent->widget), bt->widget );
+ gtk_widget_set_uposition( bt->widget, bt->realX, bt->realY );
+#endif
+ gtkControlGetSize( (wControl_p)bt );
+ if (labelStr)
+ bt->labelW = gtkAddLabel( (wControl_p)bt, labelStr );
+#ifdef USE_TEXTVIEW
+ gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(bt->text), GTK_WRAP_WORD );
+#else
+ gtk_text_set_word_wrap( GTK_TEXT(bt->text), TRUE );
+#endif
+ gtk_widget_realize( bt->text );
+ gtkAddButton( (wControl_p)bt );
+ gtkAddHelpString( bt->widget, helpStr );
+#ifdef USE_TEXTVIEW
+ g_signal_connect( G_OBJECT(tb), "changed", GTK_SIGNAL_FUNC(textChanged), bt );
+#else
+ gtk_signal_connect( GTK_OBJECT(bt->text), "changed", GTK_SIGNAL_FUNC(textChanged), bt );
+#endif
+ return bt;
+}
diff --git a/app/wlib/gtklib/gtkwindow.c b/app/wlib/gtklib/gtkwindow.c
new file mode 100644
index 0000000..b86b173
--- /dev/null
+++ b/app/wlib/gtklib/gtkwindow.c
@@ -0,0 +1,856 @@
+/** \file gtkwindow.c
+ * Basic window handling stuff.
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/gtkwindow.c,v 1.12 2010-04-28 04:04:38 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gtkint.h"
+
+wWin_p gtkMainW;
+
+#define FOUR (4)
+#define MENUH (24)
+
+#define MIN_WIN_WIDTH (50)
+#define MIN_WIN_HEIGHT (50)
+
+#define SECTIONWINDOWSIZE "gtklib window size"
+#define SECTIONWINDOWPOS "gtklib window pos"
+
+extern wBool_t listHelpStrings;
+
+static wControl_p firstWin = NULL, lastWin;
+static int keyState;
+static wBool_t gtkBlockEnabled = TRUE;
+
+/*
+ *****************************************************************************
+ *
+ * Window Utilities
+ *
+ *****************************************************************************
+ */
+
+/**
+ * Get the window size from the resource (.rc) file. The size is saved under the key
+ * SECTIONWINDOWSIZE.window name
+ *
+ * \param win IN window
+ * \param nameStr IN window name
+ */
+
+static void getWinSize( wWin_p win, const char * nameStr )
+{
+ int w, h;
+ const char *cp;
+ char *cp1, *cp2;
+
+ if ( (win->option&F_RESIZE) &&
+ (win->option&F_RECALLPOS) &&
+ (cp = wPrefGetString( SECTIONWINDOWSIZE, nameStr)) &&
+ (w = strtod( cp, &cp1 ), cp != cp1) &&
+ (h = strtod( cp1, &cp2 ), cp1 != cp2) ) {
+ if (w < 10)
+ w = 10;
+ if (h < 10)
+ h = 10;
+ win->w = win->origX = w;
+ win->h = win->origY = h;
+ win->option &= ~F_AUTOSIZE;
+ }
+}
+
+/**
+ * Save the window size to the resource (.rc) file. The size is saved under the key
+ * SECTIONWINDOWSIZE.window name
+ *
+ * \param win IN window
+ */
+
+static void saveSize( wWin_p win )
+{
+ char pos_s[20];
+ if ( (win->option&F_RESIZE) &&
+ (win->option&F_RECALLPOS) &&
+ GTK_WIDGET_VISIBLE( GTK_WIDGET(win->gtkwin) ) ) {
+ sprintf( pos_s, "%d %d", win->w, win->h-(FOUR + ((win->option&F_MENUBAR)?MENUH:0) ) );
+ wPrefSetString( SECTIONWINDOWSIZE, win->nameStr, pos_s );
+ }
+}
+
+/**
+ * Get the window position from the resource (.rc) file. The position is saved under the key
+ * SECTIONWINDOWPOS.window name
+ *
+ * \param win IN window
+ */
+
+static void getPos( wWin_p win )
+{
+ int x, y;
+ const char *cp;
+ char *cp1, *cp2;
+ wPos_t gtkDisplayWidth = gdk_screen_width();
+ wPos_t gtkDisplayHeight = gdk_screen_height();
+
+ if ( (win->option&F_RECALLPOS) &&
+ (!win->shown) ) {
+ if ((cp = wPrefGetString( SECTIONWINDOWPOS, win->nameStr))) {
+ x = strtod( cp, &cp1 );
+ if (cp == cp1)
+ return;
+ y = strtod( cp1, &cp2 );
+ if (cp2 == cp1)
+ return;
+ if ( y > gtkDisplayHeight-win->h )
+ y = gtkDisplayHeight-win->h;
+ if ( x > gtkDisplayWidth-win->w )
+ x = gtkDisplayWidth-win->w;
+ if ( x <= 0 )
+ x = 1;
+ if ( y <= 0 )
+ y = 1;
+ gtk_window_move( GTK_WINDOW(win->gtkwin), x, y );
+ gtk_window_resize( GTK_WINDOW(win->gtkwin), win->w, win->h );
+ }
+ }
+}
+
+/**
+ * Save the window position to the resource (.rc) file. The position is saved under the key
+ * SECTIONWINDOWPOS.window name
+ *
+ * \param win IN window
+ */
+
+static void savePos( wWin_p win )
+{
+ int x, y;
+ char pos_s[20];
+ if ( (win->option&F_RECALLPOS) ) {
+ gdk_window_get_position( GTK_WIDGET(win->gtkwin)->window, &x, &y );
+ x -= 5;
+ y -= 25;
+ sprintf( pos_s, "%d %d", x, y );
+ wPrefSetString( SECTIONWINDOWPOS, win->nameStr, pos_s );
+ }
+}
+
+/**
+ * Returns the dimensions of <win>.
+ *
+ * \param win IN window handle
+ * \param width OUT width of window
+ * \param height OUT height of window minus menu bar size
+ */
+
+EXPORT void wWinGetSize(
+ wWin_p win, /* Window */
+ wPos_t * width, /* Returned window width */
+ wPos_t * height ) /* Returned window height */
+{
+ GtkRequisition requisition;
+ wPos_t w, h;
+ gtk_widget_size_request( win->gtkwin, &requisition );
+ w = win->w;
+ h = win->h;
+ if ( win->option&F_AUTOSIZE ) {
+ if ( win->realX > w )
+ w = win->realX;
+ if ( win->realY > h )
+ h = win->realY;
+ }
+ *width = w;
+ *height = h - FOUR - ((win->option&F_MENUBAR)?MENUH:0);
+}
+
+/**
+ * Sets the dimensions of <w> to <widht> and <height>.
+ *
+ * \param win IN window
+ * \param width IN new width
+ * \param height IN new height
+ */
+
+EXPORT void wWinSetSize(
+ wWin_p win, /* Window */
+ wPos_t width, /* Window width */
+ wPos_t height ) /* Window height */
+{
+ win->busy = TRUE;
+ win->w = width;
+ win->h = height + FOUR + ((win->option&F_MENUBAR)?MENUH:0);
+ gtk_widget_set_size_request( win->gtkwin, win->w, win->h );
+ gtk_widget_set_size_request( win->widget, win->w, win->h );
+ win->busy = FALSE;
+
+}
+
+/**
+ * Shows or hides window <win>. If <win> is created with 'F_BLOCK' option then the applications other
+ * windows are disabled and 'wWinShow' doesnot return until the window <win> is closed by calling
+ * 'wWinShow(<win>,FALSE)'.
+ *
+ * \param win IN window
+ * \param show IN visibility state
+ */
+
+EXPORT void wWinShow(
+ wWin_p win, /* Window */
+ wBool_t show ) /* Command */
+{
+ GtkRequisition requisition;
+ if (debugWindow >= 2) printf("Set Show %s\n", win->labelStr?win->labelStr:"No label" );
+ if (win->widget == 0) abort();
+ if (show) {
+ keyState = 0;
+ getPos( win );
+ if ( win->option & F_AUTOSIZE ) {
+ gtk_widget_size_request( win->gtkwin, &requisition );
+ if ( requisition.width != win->w || requisition.height != win->h ) {
+ gtk_widget_set_size_request( win->gtkwin, win->w, win->h );
+ gtk_widget_set_size_request( win->widget, win->w, win->h );
+ if (win->option&F_MENUBAR) {
+ gtk_widget_set_size_request( win->menubar, win->w, MENUH );
+ }
+ }
+ }
+ if ( !win->shown ) {
+ gtk_widget_show( win->gtkwin );
+ gtk_widget_show( win->widget );
+ }
+ gdk_window_raise( win->gtkwin->window );
+ if ( win->shown && win->modalLevel > 0 )
+ gtk_widget_set_sensitive( GTK_WIDGET(win->gtkwin), TRUE );
+ win->shown = show;
+ win->modalLevel = 0;
+
+ if ( (!gtkBlockEnabled) || (win->option & F_BLOCK) == 0) {
+ wFlush();
+ } else {
+ gtkDoModal( win, TRUE );
+ }
+ } else {
+ wFlush();
+ saveSize( win );
+ savePos( win );
+ win->shown = show;
+ if ( gtkBlockEnabled && (win->option & F_BLOCK) != 0) {
+ gtkDoModal( win, FALSE );
+ }
+ gtk_widget_hide( win->gtkwin );
+ gtk_widget_hide( win->widget );
+ }
+}
+
+/**
+ * Block windows against user interactions. Done during demo mode etc.
+ *
+ * \param enabled IN blocked if TRUE
+ */
+
+EXPORT void wWinBlockEnable(
+ wBool_t enabled )
+{
+ gtkBlockEnabled = enabled;
+}
+
+/**
+ * Returns whether the window is visible.
+ *
+ * \param win IN window
+ * \return TRUE if visible, FALSE otherwise
+ */
+
+EXPORT wBool_t wWinIsVisible(
+ wWin_p win )
+{
+ return win->shown;
+}
+
+/**
+ * Sets the title of <win> to <title>.
+ *
+ * \param varname1 IN window
+ * \param varname2 IN new title
+ */
+
+EXPORT void wWinSetTitle(
+ wWin_p win, /* Window */
+ const char * title ) /* New title */
+{
+ gtk_window_set_title( GTK_WINDOW(win->gtkwin), title );
+}
+
+/**
+ * Sets the window <win> to busy or not busy. Sets the cursor accordingly
+ *
+ * \param varname1 IN window
+ * \param varname2 IN TRUE if busy, FALSE otherwise
+ */
+
+EXPORT void wWinSetBusy(
+ wWin_p win, /* Window */
+ wBool_t busy ) /* Command */
+{
+ GdkCursor * cursor;
+ if (win->gtkwin == 0) abort();
+ if ( busy )
+ cursor = gdk_cursor_new ( GDK_WATCH );
+ else
+ cursor = NULL;
+ gdk_window_set_cursor (win->gtkwin->window, cursor);
+ if ( cursor )
+ gdk_cursor_destroy (cursor);
+ gtk_widget_set_sensitive( GTK_WIDGET(win->gtkwin), busy==0 );
+}
+
+
+EXPORT void gtkDoModal(
+ wWin_p win0,
+ wBool_t modal )
+{
+ wWin_p win;
+ for ( win=(wWin_p)firstWin; win; win=(wWin_p)win->next ) {
+ if ( win->shown && win != win0 ) {
+ if ( modal ) {
+ if ( win->modalLevel == 0 )
+ gtk_widget_set_sensitive( GTK_WIDGET(win->gtkwin), FALSE );
+ win->modalLevel++;
+ } else {
+ if ( win->modalLevel > 0 ) {
+ win->modalLevel--;
+ if ( win->modalLevel == 0 )
+ gtk_widget_set_sensitive( GTK_WIDGET(win->gtkwin), TRUE );
+ }
+ }
+ if ( win->modalLevel < 0 ) {
+ fprintf( stderr, "DoModal: %s modalLevel < 0", win->nameStr?win->nameStr:"<NULL>" );
+ abort();
+ }
+ }
+ }
+ if ( modal ) {
+ gtk_main();
+ } else {
+ gtk_main_quit();
+ }
+}
+
+/**
+ * Returns the Title of <win>.
+ *
+ * \param win IN window
+ * \return pointer to window title
+ */
+
+EXPORT const char * wWinGetTitle(
+ wWin_p win ) /* Window */
+{
+ return win->labelStr;
+}
+
+
+EXPORT void wWinClear(
+ wWin_p win,
+ wPos_t x,
+ wPos_t y,
+ wPos_t width,
+ wPos_t height )
+{
+}
+
+
+EXPORT 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) ) {
+ gtkButtonDoAction( (wButton_p)b );
+ }
+ }
+}
+
+/*
+ ******************************************************************************
+ *
+ * Call Backs
+ *
+ ******************************************************************************
+ */
+
+static gint window_delete_event(
+ GtkWidget *widget,
+ GdkEvent *event,
+ wWin_p win )
+{
+ wControl_p b;
+ /* if you return FALSE in the "delete_event" signal handler,
+ * GTK will emit the "destroy" signal. Returning TRUE means
+ * you don't want the window to be destroyed.
+ * This is useful for popping up 'are you sure you want to quit ?'
+ * type dialogs. */
+
+ /* Change TRUE to FALSE and the main window will be destroyed with
+ * a "delete_event". */
+
+ for ( b = win->first; b; b=b->next )
+ if (b->doneProc)
+ b->doneProc( b );
+ if (win->winProc) {
+ win->winProc( win, wClose_e, win->data );
+ if (win != gtkMainW)
+ wWinShow( win, FALSE );
+ }
+ return (TRUE);
+}
+
+static int window_redraw(
+ wWin_p win,
+ wBool_t doWinProc )
+{
+ wControl_p b;
+
+ if (win==NULL)
+ return FALSE;
+
+ for (b=win->first; b != NULL; b = b->next) {
+ if (b->repaintProc)
+ b->repaintProc( b );
+ }
+
+ return FALSE;
+}
+
+static int fixed_expose_event(
+ GtkWidget * widget,
+ GdkEventExpose * event,
+ wWin_p win )
+{
+ if (event->count==0)
+ return window_redraw( win, TRUE );
+ else
+ return FALSE;
+}
+
+static int window_configure_event(
+ GtkWidget * widget,
+ GdkEventConfigure * event,
+ wWin_p win )
+{
+ wPos_t h;
+
+ if (win==NULL)
+ return FALSE;
+
+ h = event->height - FOUR;
+ if (win->option&F_MENUBAR)
+ h -= MENUH;
+ if (win->option&F_RESIZE) {
+ if ( event->width < 10 || event->height < 10 )
+ return TRUE;
+ if (win->w != event->width || win->h != event->height) {
+ win->w = event->width;
+ win->h = event->height;
+ if ( win->w < MIN_WIN_WIDTH )
+ win->w = MIN_WIN_WIDTH;
+ if ( win->h < MIN_WIN_HEIGHT )
+ win->h = MIN_WIN_HEIGHT;
+ if (win->option&F_MENUBAR)
+ gtk_widget_set_size_request( win->menubar, win->w, MENUH );
+
+ if (win->busy==FALSE && win->winProc) {
+ win->winProc( win, wResize_e, win->data );
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Get current state of shift, ctrl or alt keys.
+ *
+ * \return or'ed value of WKEY_SHIFT, WKEY_CTRL and WKEY_ALT depending on state
+ */
+
+int wGetKeyState( void )
+{
+ return keyState;
+}
+
+wBool_t catch_shift_ctrl_alt_keys(
+ GtkWidget * widget,
+ GdkEventKey *event,
+ void * data )
+{
+ int state;
+
+ state = 0;
+ switch (event->keyval) {
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ state |= WKEY_SHIFT;
+ break;
+ case GDK_Control_L:
+ case GDK_Control_R:
+ state |= WKEY_CTRL;
+ break;
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ state |= WKEY_ALT;
+ break;
+ }
+ if ( state != 0 ) {
+ if (event->type == GDK_KEY_PRESS)
+ keyState |= state;
+ else
+ keyState &= ~state;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gint window_char_event(
+ GtkWidget * widget,
+ GdkEventKey *event,
+ wWin_p win )
+{
+ wControl_p bb;
+ if ( catch_shift_ctrl_alt_keys( widget, event, win ) )
+ return FALSE;
+ if (event->type == GDK_KEY_RELEASE)
+ return FALSE;
+
+ if ( event->state == 0 ) {
+ if ( event->keyval == GDK_Escape ) {
+ for ( bb=win->first; bb; bb=bb->next ) {
+ if ( bb->type == B_BUTTON && (bb->option&BB_CANCEL) ) {
+ gtkButtonDoAction( (wButton_p)bb );
+ return TRUE;
+ }
+ }
+ }
+ }
+ if ( gtkHandleAccelKey( event ) ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * Main and Popup Windows
+ *
+ *******************************************************************************
+ */
+
+
+
+static wWin_p wWinCommonCreate(
+ wWin_p parent,
+ int winType,
+ wPos_t x,
+ wPos_t y,
+ const char * labelStr,
+ const char * nameStr,
+ long option,
+ wWinCallBack_p winProc,
+ void * data )
+{
+ wWin_p w;
+ int h;
+
+ w = gtkAlloc( NULL, winType, x, y, labelStr, sizeof *w, data );
+ w->busy = TRUE;
+ w->option = option;
+ getWinSize( w, nameStr );
+
+ h = FOUR;
+ if (w->option&F_MENUBAR)
+ h += MENUH;
+
+ if ( winType == W_MAIN ) {
+ w->gtkwin = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ } else {
+ w->gtkwin = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ if ( gtkMainW )
+ gtk_window_set_transient_for( GTK_WINDOW(w->gtkwin), GTK_WINDOW(gtkMainW->gtkwin) );
+ }
+
+ if( option & F_HIDE )
+ gtk_widget_hide( w->gtkwin );
+
+ /* center window on top of parent window */
+ if( option & F_CENTER )
+ gtk_window_set_position(GTK_WINDOW(w->gtkwin), GTK_WIN_POS_CENTER_ON_PARENT );
+
+ w->widget = gtk_fixed_new();
+ if (w->widget == 0) abort();
+
+ if (w->option&F_MENUBAR) {
+ w->menubar = gtk_menu_bar_new();
+ gtk_container_add( GTK_CONTAINER(w->widget), w->menubar );
+ gtk_widget_show( w->menubar );
+ gtk_widget_set_size_request( w->menubar, -1, MENUH );
+ }
+
+ gtk_container_add( GTK_CONTAINER(w->gtkwin), w->widget );
+
+ if (w->option&F_AUTOSIZE) {
+ w->realX = 0;
+ w->w = 0;
+ w->realY = h;
+ w->h = 0;
+ } else {
+ w->w = w->realX = w->origX;
+ w->h = w->realY = w->origY+h;
+ gtk_widget_set_size_request( w->gtkwin, w->w, w->h );
+ gtk_widget_set_size_request( w->widget, w->w, w->h );
+ if (w->option&F_MENUBAR) {
+ gtk_widget_set_size_request( w->menubar, w->w, MENUH );
+ }
+ }
+
+ w->first = w->last = NULL;
+
+ w->winProc = winProc;
+
+ gtk_signal_connect (GTK_OBJECT (w->gtkwin), "delete_event",
+ GTK_SIGNAL_FUNC (window_delete_event), w);
+ gtk_signal_connect (GTK_OBJECT (w->widget), "expose_event",
+ GTK_SIGNAL_FUNC (fixed_expose_event), w);
+ gtk_signal_connect (GTK_OBJECT (w->gtkwin), "configure_event",
+ GTK_SIGNAL_FUNC (window_configure_event), w);
+ gtk_signal_connect (GTK_OBJECT (w->gtkwin), "key_press_event",
+ GTK_SIGNAL_FUNC (window_char_event), w);
+ gtk_signal_connect (GTK_OBJECT (w->gtkwin), "key_release_event",
+ GTK_SIGNAL_FUNC (window_char_event), w);
+ gtk_widget_set_events (w->widget, GDK_EXPOSURE_MASK );
+ gtk_widget_set_events ( GTK_WIDGET(w->gtkwin), GDK_EXPOSURE_MASK|GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK );
+
+ /**
+ * \todo { set_policy is deprecated and should be replaced by set_resizable. In order to do that
+ * the library has to be cleared up from calls to set_size_request as these set the minimum widget size
+ * to the current size preventing the user from re-sizing the window to a smaller size. At least this
+ * is my current assumption ;-) }
+ */
+ if (w->option & F_RESIZE) {
+ gtk_window_set_policy( GTK_WINDOW(w->gtkwin), TRUE, TRUE, TRUE );
+// gtk_window_set_resizable( GTK_WINDOW(w->gtkwin), TRUE );
+ } else {
+// gtk_window_set_resizable( GTK_WINDOW(w->gtkwin), FALSE );
+ gtk_window_set_policy( GTK_WINDOW(w->gtkwin), FALSE, FALSE, TRUE );
+ }
+
+ w->lastX = 0;
+ w->lastY = h;
+ w->shown = FALSE;
+ w->nameStr = nameStr?strdup( nameStr ):NULL;
+ if (labelStr)
+ gtk_window_set_title( GTK_WINDOW(w->gtkwin), labelStr );
+ if (listHelpStrings)
+ printf( "WINDOW - %s\n", nameStr?nameStr:"<NULL>" );
+
+ if (firstWin) {
+ lastWin->next = (wControl_p)w;
+ } else {
+ firstWin = (wControl_p)w;
+ }
+ lastWin = (wControl_p)w;
+ gtk_widget_show( w->widget );
+ gtk_widget_realize( w->gtkwin );
+
+ w->busy = FALSE;
+ return w;
+}
+
+/**
+ * \todo { investigate and implement this function for setting the correct icon as necessary.
+ * It looks like these functions are never called at the moment. }
+ */
+
+EXPORT void wWinSetBigIcon(
+ wWin_p win, /* Main window */
+ wIcon_p ip ) /* The icon */
+/*
+Create an Icon from a X-bitmap.
+*/
+{
+#ifdef LATER
+ GdkPixmap * pixmap;
+ GdkBitmap * mask;
+ pixmap = gtkMakeIcon( win->gtkwin, ip, &mask );
+ gdk_window_set_icon( win->gtkwin->window, NULL, pixmap, mask );
+ gdk_pixmap_unref( pixmap );
+ gdk_bitmap_unref( mask );
+#endif
+}
+
+
+/**
+ * \todo { investigate and implement this function for setting the correct icon as necessary.
+ * It looks like these functions are never called at the moment. }
+ */
+
+
+EXPORT void wWinSetSmallIcon(
+ wWin_p win, /* Main window */
+ wIcon_p ip ) /* The icon */
+/*
+Create an Icon from a X-bitmap.
+*/
+{
+ GdkBitmap * mask;
+ if ( ip->gtkIconType == gtkIcon_bitmap ) {
+ mask = gdk_bitmap_create_from_data( win->gtkwin->window, ip->bits, ip->w, ip->h );
+ gdk_window_set_icon( win->gtkwin->window, NULL, mask, mask );
+ /*gdk_bitmap_unref( mask );*/
+ }
+}
+
+/**
+ * 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 Initial window width
+ * \param y IN Initial window height
+ * \param helpStr IN Help topic string
+ * \param labelStr IN window title
+ * \param nameStr IN Window name
+ * \param option IN options for window creation
+ * \param winProc IN pointer to main window procedure
+ * \param data IN User context
+ * \return window handle or NULL on error
+ */
+
+EXPORT wWin_p wWinMainCreate(
+ const char * name, /* Application name */
+ wPos_t x, /* Initial window width */
+ wPos_t y, /* Initial window height */
+ const char * helpStr, /* Help topic string */
+ const char * labelStr, /* Window title */
+ const char * nameStr, /* Window name */
+ long option, /* Options */
+ wWinCallBack_p winProc, /* Call back function */
+ void * data ) /* User context */
+{
+ char *pos;
+
+ if( pos = strchr( name, ';' )) {
+ /* if found, split application name and configuration name */
+ strcpy( wConfigName, pos + 1 );
+ } else {
+ /* if not found, application name and configuration name are same */
+ strcpy( wConfigName, name );
+ }
+
+ gtkMainW = wWinCommonCreate( NULL, W_MAIN, x, y, labelStr, nameStr, option, winProc, data );
+
+ wDrawColorWhite = wDrawFindColor( 0xFFFFFF );
+ wDrawColorBlack = wDrawFindColor( 0x000000 );
+
+ gdk_window_set_group( gtkMainW->gtkwin->window, gtkMainW->gtkwin->window );
+ return gtkMainW;
+}
+
+/**
+ * Create a new popup window.
+ *
+ * \param parent IN Parent window (may be NULL)
+ * \param x IN Initial window width
+ * \param y IN Initial window height
+ * \param helpStr IN Help topic string
+ * \param labelStr IN Window title
+ * \param nameStr IN Window name
+ * \param option IN Options
+ * \param winProc IN call back function
+ * \param data IN User context information
+ * \return handle for new window
+ */
+
+EXPORT wWin_p wWinPopupCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ const char * labelStr,
+ const char * nameStr,
+ long option,
+ wWinCallBack_p winProc,
+ void * data )
+{
+ wWin_p win;
+
+ if (parent == NULL) {
+ if (gtkMainW == NULL)
+ abort();
+ parent = gtkMainW;
+ }
+ win = wWinCommonCreate( parent, W_POPUP, x, y, labelStr, nameStr, option, winProc, data );
+ gdk_window_set_group( win->gtkwin->window, gtkMainW->gtkwin->window );
+
+ return win;
+}
+
+
+/**
+ * Terminates the applicaton with code <rc>. Before closing the main window
+ * call back is called with wQuit_e. The program is terminated without exiting
+ * the main message loop.
+ *
+ * \param rc IN exit code
+ * \return never returns
+ */
+
+
+EXPORT void wExit(
+ int rc ) /* Application return code */
+{
+ wWin_p win;
+ for ( win = (wWin_p)firstWin; win; win = (wWin_p)win->next ) {
+ if ( GTK_WIDGET_VISIBLE( GTK_WIDGET(win->gtkwin) ) ) {
+ saveSize( win );
+ savePos( win );
+ }
+ }
+ wPrefFlush();
+ if (gtkMainW && gtkMainW->winProc != NULL)
+ gtkMainW->winProc( gtkMainW, wQuit_e, gtkMainW->data );
+
+ exit( rc );
+}
diff --git a/app/wlib/gtklib/gtkxpm.c b/app/wlib/gtklib/gtkxpm.c
new file mode 100644
index 0000000..022c973
--- /dev/null
+++ b/app/wlib/gtklib/gtkxpm.c
@@ -0,0 +1,177 @@
+/** \file gtkxpm.c
+ * XPM creation functions
+ */
+
+/* XTrackCad - Model Railroad CAD
+ * Copyright (C) 2015 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 <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include "gtkint.h"
+
+ #include "uthash.h"
+
+struct xpmColTable {
+ int color; /* color value (rgb) */
+ char name[ 5 ]; /* corresponding character representation */
+ UT_hash_handle hh; /* makes this structure hashable */
+};
+
+static struct xpmColTable *colTable = NULL;
+
+// must be 64 chars long
+static char colVal[] = ".*0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+
+struct wDraw_t {
+ WOBJ_COMMON
+ void * context;
+ wDrawActionCallBack_p action;
+ wDrawRedrawCallBack_p redraw;
+
+ GdkPixmap * pixmap;
+ GdkPixmap * pixmapBackup;
+
+ double dpi;
+
+ GdkGC * gc;
+ wDrawWidth lineWidth;
+ wDrawOpts opts;
+ wPos_t maxW;
+ wPos_t maxH;
+ unsigned long lastColor;
+ wBool_t lastColorInverted;
+ const char * helpStr;
+
+ wPos_t lastX;
+ wPos_t lastY;
+
+ wBool_t delayUpdate;
+ };
+
+ /**
+ * Export as XPM bitmap file. During creation of the color table, a 4 byte color
+ * encoding is assumed and a table created accordingly. Once the whole picture has been scanned
+ * the correct number ist known. When writing to disk only the needed number of bytes per entry
+ * is written.
+ * This routine was heavily inspired by on implementation for TK written by Jan Nijtmans.
+ *
+ * \param d IN the drawing area ?
+ * \param fileName IN fully qualified filename for the bitmap file.
+ * \return TRUE on success, FALSE on error
+ */
+
+wBool_t wBitMapWriteFile( wDraw_p d, const char * fileName )
+{
+ GdkImage * image;
+ gint x, y;
+ guint32 pixel;
+ FILE * f;
+ int cc = 0;
+ struct xpmColTable *ct, *tmp;
+ int numChars;
+
+ image = gdk_image_get( (GdkWindow*)d->pixmap, 0, 0, d->w, d->h );
+ if (!image) {
+ wNoticeEx( NT_ERROR, "WriteBitMap: image_get failed", "Ok", NULL );
+ return FALSE;
+ }
+
+ f = fopen( fileName, "w" );
+ if (!f) {
+ perror( fileName );
+ return FALSE;
+ }
+ fprintf( f, "/* XPM */\n" );
+ fprintf( f, "static char * xtrkcad_bitmap[] = {\n" );
+ fprintf( f, "/* width height num_colors chars_per_pixel */\n" );
+
+ // count colors used and create the color table in the same pass
+ for( y = 0; y < d->h;y ++ ) {
+ for (x = 0; x < d->w; x++ ) {
+
+ pixel = gdk_image_get_pixel( image, x, y );
+ //check whether color is new
+
+ HASH_FIND(hh, colTable, &pixel, sizeof( guint32 ), ct);
+ if( !ct ) {
+ // not found previously, so add a new color table entry
+ int i;
+ int c;
+
+ ct = malloc( sizeof( struct xpmColTable ) );
+ ct->name[ 4 ] = '\0';
+ for( i = 3, c = cc; i >= 0; i--, c>>=6 ) {
+ (ct->name)[ i ] = colVal[ c & 0x3F ];
+ }
+ ct->color = pixel;
+
+ HASH_ADD(hh, colTable, color, sizeof( guint32 ), ct);
+ cc++;
+ }
+ }
+ }
+
+ // calculate how many characters are needed for the color table
+ numChars = 1;
+ if( cc > 0x3ffff ) {
+ numChars = 4;
+ } else {
+ if( cc > 0xfff ) {
+ numChars = 3;
+ } else {
+ if( cc > 0x3f ) {
+ numChars = 2;
+ }
+ }
+ }
+ // print color table
+ fprintf( f, "\"%d %d %d %d\"\n", d->w, d->h, cc, numChars );
+ fprintf( f, "/* colors */\n" );
+ for( ct = colTable; ct != NULL; ct = ct->hh.next )
+ fprintf( f, "\"%s c #%6.6x\",\n", (ct->name) + (4 - numChars ), ct->color );
+
+ // print the pixels
+ fprintf( f, "/* pixels */\n" );
+ for ( y=0; y<d->h; y++ ) {
+ fprintf( f, "\"" );
+ for ( x=0; x<d->w; x++ ) {
+ pixel = gdk_image_get_pixel( image, x, y );
+ HASH_FIND( hh, colTable, &pixel, sizeof(guint32), ct );
+ fputs( (ct->name) + (4 - numChars ), f );
+ }
+ fprintf( f, "\"%s\n", (y<d->h-1)?",":"" );
+ }
+
+ // delete the hash and free the content
+ HASH_ITER(hh, colTable, ct, tmp) {
+ HASH_DEL(colTable,ct);
+ free(ct);
+ }
+
+ gdk_image_destroy( image );
+ fprintf( f, "};\n" );
+ fclose( f );
+ return TRUE;
+}
diff --git a/app/wlib/gtklib/psprint.c b/app/wlib/gtklib/psprint.c
new file mode 100644
index 0000000..8e7cbe6
--- /dev/null
+++ b/app/wlib/gtklib/psprint.c
@@ -0,0 +1,1599 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/psprint.c,v 1.5 2009-05-15 18:54:20 m_fischer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <pwd.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <math.h>
+#include <locale.h>
+
+#include <stdint.h>
+
+#include <gtk/gtk.h>
+
+#include "gtkint.h"
+#include "wlib.h"
+/* #include "dynarr.h" */
+#include "i18n.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+#define MM(m) ((m)/25.4)
+
+/* char * gtkFontTranslate( wFont_p ); */
+extern wDrawColor wDrawColorWhite;
+extern wDrawColor wDrawColorBlack;
+
+/*****************************************************************************
+ *
+ * MACROS
+ *
+ */
+
+#define PRINT_COMMAND (0)
+#define PRINT_FILE (1)
+
+#define PRINT_PORTRAIT (0)
+#define PRINT_LANDSCAPE (1)
+
+/* #define MAXIMUM(a,b) ((a)>(b) ? (a) : (b)) */
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#define PPI (72.0)
+#define P2I( P ) ((P)/PPI)
+
+#define DPI (1440.0)
+#define D2I( D ) (((double)(D))/DPI)
+
+#define CENTERMARK_LENGTH 60
+
+#define WFONT "WFONT"
+#define WPRINTER "WPRINTER"
+#define WMARGIN "WMARGIN"
+#define WMARGINMAP "WMARGINMAP"
+#define WPRINTFONT "WPRINTFONT"
+
+/*****************************************************************************
+ *
+ * VARIABLES
+ *
+ */
+
+extern struct wDraw_t psPrint_d;
+
+/*
+typedef struct {
+ wIndex_t cmdOrFile;
+ FILE * f;
+ } wPrinterStream_t;
+typedef wPrinterStream_t * wPrinterStream_p;
+*/
+static wBool_t printContinue;
+static wWin_p printAbortW;
+static wMessage_p printAbortT;
+static wMessage_p printAbortM;
+
+static wWin_p printFileW;
+static wWin_p newFontAliasW;
+static wWin_p printSetupW;
+static wList_p optPrinterB;
+static wList_p optPaperSizeB;
+static wMessage_p newFontAliasXFntB;
+static wList_p optMarginB;
+static wButton_p optMarginDelB;
+static wFloat_p optTopMargin;
+static wFloat_p optBottomMargin;
+static wFloat_p optRightMargin;
+static wFloat_p optLeftMargin;
+static wChoice_p optFormat;
+static wList_p optXFontL;
+static wString_p optPSFontS;
+static wFloat_p optFontSizeFactor;
+static long optXFontX;
+static const char * optXFont;
+static char optPSFont[200];
+
+#ifdef LATER
+static char addPrinterName[80];
+static char addPrinterCommand[80];
+static wWin_p addPrinterW;
+static wString_p addPrinterN;
+static wString_p addPrinterC;
+static char addMarginName[80];
+static wWin_p addMarginW;
+static wString_p addMarginN;
+#endif
+
+static FILE * psFile;
+static wPrinterStream_p psFileStream;
+static wIndex_t pageCount;
+static wIndex_t totalPageCount;
+
+static long newPPrinter;
+static long newPPaper;
+static wPrintSetupCallBack_p printSetupCallBack;
+
+static double tBorder;
+static double rBorder;
+static double lBorder;
+static double bBorder;
+
+static long printFormat = PRINT_LANDSCAPE;
+static double currLineWidth = 0;
+
+static long curPrinter = 0;
+static char *sPrintFileName;
+static long curMargin = 0;
+
+static const char * prefName;
+static const char * prefPaper;
+static const char * prefMargin;
+static const char * prefFormat;
+
+static char newMarginName[256];
+
+typedef enum { PS_LT_SOLID, PS_LT_DASH } PS_LT_E;
+static PS_LT_E currentLT = PS_LT_SOLID;
+
+static double fontSizeFactor = 1.0;
+
+static struct {
+ const char * name;
+ double w, h;
+ } papers[] = {
+ { "Letter", 8.5, 11.0 },
+ { "Legal", 8.5, 14.0 },
+ { "Tabloid", 11.0, 17.0 },
+ { "Ledger", 17.0, 11.0 },
+ { "Fan Fold", 13.2, 11.0 },
+ { "Statement", 5.5, 8.5 },
+ { "Executive", 7.5, 10.0 },
+ { "Folio", 8.27, 13 },
+ { "A0", MM(841), MM(1189) },
+ { "A1", MM(594), MM(841) },
+ { "A2", MM(420), MM(594) },
+ { "A3", MM(297), MM(420) },
+ { "A4", MM(210), MM(297) },
+ { "A5", MM(148), MM(210) },
+ { "A6", MM(105), MM(148) },
+ { "A7", MM(74), MM(105) },
+ { "A8", MM(52), MM(74) },
+ { "A9", MM(37), MM(52) },
+ { "A10", MM(26), MM(37) },
+ { "B0", MM(1000), MM(1414) },
+ { "B1", MM(707), MM(1000) },
+ { "B2", MM(500), MM(707) },
+ { "B3", MM(353), MM(500) },
+ { "B4", MM(250), MM(353) },
+ { "B5", MM(176), MM(250) },
+ { "B6", MM(125), MM(176) },
+ { "B7", MM(88), MM(125) },
+ { "B8", MM(62), MM(88) },
+ { "B9", MM(44), MM(62) },
+ { "B10", MM(31), MM(44) },
+ { "C0", MM(917), MM(1297) },
+ { "C1", MM(648), MM(917) },
+ { "C2", MM(458), MM(648) },
+ { "C3", MM(324), MM(458) },
+ { "C4", MM(229), MM(324) },
+ { "C5", MM(162), MM(229) },
+ { "C6", MM(114), MM(162) },
+ { "C7", MM(81), MM(114) },
+ { "DL", MM(110), MM(220) },
+ { NULL } };
+wIndex_t curPaper = 0;
+
+typedef struct {
+ const char * name;
+ const char * cmd;
+ wIndex_t class;
+ } printers_t;
+dynArr_t printers_da;
+#define printers(N) DYNARR_N(printers_t,printers_da,N)
+
+typedef struct {
+ const char * name;
+ double t, b, r, l;
+ } margins_t;
+dynArr_t margins_da;
+#define margins(N) DYNARR_N(margins_t,margins_da,N)
+
+static void printFileNameSel( void * junk );
+static void printInit( void );
+
+/*
+ * Stuff related to determining the list of fonts used in the
+ * Postscript file. A simple linked-list is used to implement a
+ * stack. Everything is specialized to this application.
+ */
+
+/**
+ * Nodes of the \a fontsUsed list.
+ */
+struct list_node {
+ struct list_node *next;
+ char *data;
+} ;
+
+/**
+ * Pointer to the \a fontsUsed list.
+ */
+static struct list_node *fontsUsed = NULL;
+
+
+/**
+ * Pushes its argument on to the \a fontsUsed list.
+ * \param item - IN pointer to a string to put on the list
+ * \return nothing
+ */
+void fontsUsedPush( const char *item) {
+ struct list_node *newitem;
+ newitem = malloc(sizeof(struct list_node));
+ if (newitem == NULL) exit (2);
+ newitem->next=fontsUsed;
+ newitem->data = strdup(item);
+ if (newitem->data == NULL) exit(3);
+ fontsUsed=newitem;
+}
+
+/**
+ * Pops the top node from the \a fontsUsed list.
+ * Note that a pointer to the complete node is returned. The
+ * caller is responsible for freeing both the data and the list
+ * node when it is finished using them.
+ * \return pointer to the list node.
+ */
+struct list_node * fontsUsedPop() {
+ struct list_node *item;
+ if (fontsUsed == NULL) return NULL;
+ item = fontsUsed;
+ fontsUsed = item->next;
+ return item ;
+}
+
+/**
+ * \a fontsUsed list (re-)initializer.
+ */
+void fontsUsedInit() {
+ struct list_node *p;
+ while ((p=fontsUsedPop()) != NULL) {
+ free(p->data);
+ free(p);
+ }
+ fontsUsed=NULL;
+}
+
+/**
+ * Checks if \a s is already in \a fontsUsed list.
+ * \param s - IN string to be checked.
+ * \return TRUE if found, FALSE if not.
+ */
+int fontsUsedContains( const char *s ) {
+ struct list_node *ptr;
+ ptr = fontsUsed;
+ while ( ptr != NULL ) {
+ if ( strcmp(s, ptr->data) == 0 ) return TRUE;
+ ptr= ptr->next;
+ }
+ return FALSE ;
+}
+
+/**
+ * Adds the \a fontName to the list of fonts being used.
+ * Only if it is not already in the list.
+ *
+ * This function should be called anywhere the string "findfont"
+ * is being emitted to the Postscript file.
+ * \param \a fontName IN - string contaning the name to add.
+ */
+void addFontName( const char * fontName){
+ if (fontsUsedContains(fontName)) return;
+ fontsUsedPush(fontName);
+}
+
+/* ***************************************** */
+
+/**
+ * This function does a normal printf but uses the default C
+ * locale as decimal separator.
+ *
+ * \param template IN printf-like format string
+ * ... IN parameters according to format string
+ * \return describe the return value
+ */
+
+static void
+psPrintf (FILE *ps, const char *template, ...)
+{
+ va_list ap;
+
+ setlocale( LC_NUMERIC, "C" );
+
+ va_start( ap, template );
+ vfprintf( ps, template, ap );
+ va_end( ap );
+
+ setlocale( LC_NUMERIC, "" );
+}
+
+void wPrintSetup( wPrintSetupCallBack_p callback )
+{
+ printInit();
+ newPPrinter = curPrinter;
+ newPPaper = curPaper;
+ printSetupCallBack = callback;
+ wListSetIndex( optPrinterB, newPPrinter );
+ wListSetIndex( optPaperSizeB, newPPaper );
+ wWinShow( printSetupW, TRUE );
+}
+
+static void pSetupOk( void )
+{
+ curPrinter = newPPrinter;
+ curPaper = newPPaper;
+ wWinShow( printSetupW, FALSE );
+ wPrefSetString( "printer", "name", printers(curPrinter).name );
+ wPrefSetString( "printer", "paper", papers[curPaper].name );
+ if ( curMargin < margins_da.cnt )
+ wPrefSetString( "printer", "margin", margins(curMargin).name );
+ wPrefSetString( "printer", "format", (printFormat==PRINT_LANDSCAPE?"landscape":"portrait") );
+ if (printSetupCallBack)
+ printSetupCallBack( TRUE );
+ wPrefSetFloat( WPRINTFONT, "factor", fontSizeFactor );
+}
+
+static void pSetupCancel( void )
+{
+ wWinShow( printSetupW, FALSE );
+ if (printSetupCallBack)
+ printSetupCallBack( FALSE );
+}
+
+
+/*****************************************************************************
+ *
+ * PRINTER LIST MANAGEMENT
+ *
+ */
+
+
+static wBool_t wPrintNewPrinter(
+ const char * name )
+{
+ char * cp;
+ const char *cpEqual;
+
+ printInit();
+ DYNARR_APPEND( printers_t, printers_da, 10 );
+ cpEqual = strchr( name, '=' );
+ if (cpEqual == NULL) {
+ printers(printers_da.cnt-1).cmd = strdup( "lpr -P%s" );
+ printers(printers_da.cnt-1).name = name;
+ } else {
+ cp = strdup( name );
+ cp[cpEqual-name] = 0;
+ printers(printers_da.cnt-1).name = cp;
+ printers(printers_da.cnt-1).cmd = cp+(cpEqual-name+1);
+ name = cp;
+ }
+ if (optPrinterB) {
+ wListAddValue( optPrinterB, printers(printers_da.cnt-1).name, NULL, (void*)(intptr_t)(printers_da.cnt-1) );
+ if ( prefName && strcasecmp( prefName, name ) == 0 ) {
+ curPrinter = printers_da.cnt-1;
+ wListSetIndex( optPrinterB, curPrinter );
+ }
+ }
+ return TRUE;
+}
+
+
+static void doMarginSel(
+ wIndex_t inx,
+ const char * name,
+ wIndex_t op,
+ void * listData,
+ void * itemData )
+{
+ margins_t * p;
+ static margins_t dummy = { "", 0, 0, 0, 0 };
+ if ( inx < 0 ) {
+ for ( inx=0,p=&margins(0); inx<margins_da.cnt; inx++,p++ ) {
+ if ( strcasecmp( name, margins(inx).name ) == 0 )
+ break;
+ }
+ if ( inx >= margins_da.cnt ) {
+ strncpy( newMarginName, name, sizeof newMarginName );
+ p = &dummy;
+ }
+ } else {
+ p = &margins(inx);
+ }
+ curMargin = inx;
+ tBorder = p->t;
+ bBorder = p->b;
+ rBorder = p->r;
+ lBorder = p->l;
+ wFloatSetValue( optTopMargin, tBorder );
+ wFloatSetValue( optBottomMargin, bBorder );
+ wFloatSetValue( optRightMargin, rBorder );
+ wFloatSetValue( optLeftMargin, lBorder );
+}
+
+static wIndex_t wPrintNewMargin(
+ const char * name,
+ const char * value )
+{
+ margins_t * m;
+ int rc;
+ DYNARR_APPEND( margins_t, margins_da, 10 );
+ m = &margins(margins_da.cnt-1);
+
+ setlocale( LC_NUMERIC, "C" );
+ if ((rc=sscanf( value, "%lf %lf %lf %lf", &m->t, &m->b, &m->r, &m->l ))!=4) {
+ margins_da.cnt--;
+ setlocale( LC_NUMERIC, "" );
+ return FALSE;
+ }
+ setlocale( LC_NUMERIC, "" );
+
+ m->name = strdup( name );
+ if (optMarginB)
+ wListAddValue( optMarginB, name, NULL, NULL );
+ if ( prefMargin && strcasecmp( prefMargin, name ) == 0 ) {
+ curMargin = margins_da.cnt-1;
+ wListSetIndex( optMarginB, curMargin );
+ tBorder = m->t;
+ bBorder = m->b;
+ rBorder = m->r;
+ lBorder = m->l;
+ wFloatSetValue( optTopMargin, tBorder );
+ wFloatSetValue( optBottomMargin, bBorder );
+ wFloatSetValue( optRightMargin, rBorder );
+ wFloatSetValue( optLeftMargin, lBorder );
+ }
+ return TRUE;
+}
+
+
+static void doChangeMargin( void )
+{
+ static char marginValue[256];
+ margins_t * m;
+ sprintf( marginValue, "%0.3f %0.3f %0.3f %0.3f", tBorder, bBorder, rBorder, lBorder );
+ if ( curMargin >= margins_da.cnt ) {
+ DYNARR_APPEND( margins_t, margins_da, 10 );
+ curMargin = margins_da.cnt-1;
+ margins(curMargin).name = strdup( newMarginName );
+ wListAddValue( optMarginB, margins(curMargin).name, NULL, NULL );
+ wListSetIndex( optMarginB, curMargin );
+ }
+ m = &margins(curMargin);
+ m->t = tBorder;
+ m->b = bBorder;
+ m->r = rBorder;
+ m->l = lBorder;
+ wPrefSetString( WMARGIN, m->name, marginValue );
+}
+
+
+static void doMarginDelete( void )
+{
+ int inx;
+ if ( curMargin >= margins_da.cnt || margins_da.cnt <= 1 || curMargin == 0 )
+ return;
+ wPrefSetString( WMARGIN, margins(curMargin).name, "" );
+ free( (char*)margins(curMargin).name );
+ for ( inx=curMargin+1; inx<margins_da.cnt; inx++ )
+ margins(inx-1) = margins(inx);
+ margins_da.cnt--;
+ wListDelete( optMarginB, curMargin );
+ if ( curMargin >= margins_da.cnt )
+ curMargin--;
+ doMarginSel( curMargin, margins(curMargin).name, 0, NULL, NULL );
+}
+
+
+static const char * curPsFont = NULL;
+static const char * curXFont = NULL;
+
+
+static void newFontAliasSel( const char * alias, void * data )
+{
+ wPrefSetString( WFONT, curXFont, alias );
+ curPsFont = wPrefGetString( WFONT, curXFont );
+ wWinShow( newFontAliasW, FALSE );
+ wListAddValue( optXFontL, curXFont, NULL, NULL );
+}
+
+
+static const char * findPSFont( wFont_p fp )
+{
+ const char *f;
+ static const char * oldXFont = NULL;
+
+ curXFont = gtkFontTranslate(fp);
+ if (curXFont != NULL &&
+ oldXFont != NULL &&
+ strcasecmp(oldXFont, curXFont) == 0 &&
+ curPsFont != NULL )
+ return curPsFont;
+ if (curXFont == NULL)
+ return "Times-Roman";
+ oldXFont = curXFont;
+ printInit();
+ f = wPrefGetString( WFONT, curXFont );
+ if (f)
+ return curPsFont = f;
+ wMessageSetValue( newFontAliasXFntB, curXFont );
+ wWinShow( newFontAliasW, TRUE );
+ return curPsFont;
+}
+
+/*****************************************************************************
+ *
+ * BASIC PRINTING
+ *
+ */
+
+static void setLineType(
+ double lineWidth,
+ wDrawLineType_e lineType,
+ wDrawOpts opts )
+{
+ PS_LT_E want;
+
+ if (lineWidth < 0.0) {
+ lineWidth = P2I(-lineWidth)*2.0;
+ }
+
+ if (lineWidth != currLineWidth) {
+ currLineWidth = lineWidth;
+ psPrintf( psFile, "%0.3f setlinewidth\n", currLineWidth / (PPI*10) );
+ }
+
+ if (lineType == wDrawLineDash)
+ want = PS_LT_DASH;
+ else
+ want = PS_LT_SOLID;
+ if (want != currentLT) {
+ currentLT = want;
+ switch (want) {
+ case PS_LT_DASH:
+ psPrintf( psFile, "[%0.3f %0.3f] 0 setdash\n", P2I(2), P2I(2) );
+ break;
+ case PS_LT_SOLID:
+ psPrintf( psFile, "[] 0 setdash\n" );
+ break;
+ }
+ }
+}
+
+
+void psSetColor(
+ wDrawColor color )
+{
+ static long currColor = 0;
+ long newColor;
+
+ newColor = wDrawGetRGB( color );
+ if (newColor != currColor) {
+ psPrintf( psFile, "%0.3f %0.3f %0.3f setrgbcolor\n",
+ (float)((newColor>>16)&0xFF)/256.0,
+ (float)((newColor>>8)&0xFF)/256.0,
+ (float)((newColor)&0xFF)/256.0 );
+ currColor = newColor;
+ }
+}
+
+
+void psPrintLine(
+ wPos_t x0, wPos_t y0,
+ wPos_t x1, wPos_t y1,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ if (color == wDrawColorWhite)
+ return;
+ if (opts&wDrawOptTemp)
+ return;
+ psSetColor(color);
+ setLineType( width, lineType, opts );
+ psPrintf(psFile,
+ "%0.3f %0.3f moveto %0.3f %0.3f lineto closepath stroke\n",
+ D2I(x0), D2I(y0), D2I(x1), D2I(y1) );
+}
+
+/**
+ * Print an arc around a specified center
+ *
+ * \param x0, y0 IN center of arc
+ * \param r IN radius
+ * \param angle0, angle1 IN start and end angle
+ * \param drawCenter draw marking for center
+ * \param width line width
+ * \param lineType
+ * \param color color
+ * \param opts ?
+ */
+
+void psPrintArc(
+ wPos_t x0, wPos_t y0,
+ wPos_t r,
+ double angle0,
+ double angle1,
+ wBool_t drawCenter,
+ wDrawWidth width,
+ wDrawLineType_e lineType,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ if (color == wDrawColorWhite)
+ return;
+ if (opts&wDrawOptTemp)
+ return;
+ psSetColor(color);
+ setLineType(width, lineType, opts);
+ if (angle1 >= 360.0)
+ angle1 = 359.999;
+ angle1 = 90.0-(angle0+angle1);
+ while (angle1 < 0.0) angle1 += 360.0;
+ while (angle1 >= 360.0) angle1 -= 360.0;
+ angle0 = 90.0-angle0;
+ while (angle0 < 0.0) angle0 += 360.0;
+ while (angle0 >= 360.0) angle0 -= 360.0;
+ psPrintf(psFile,
+ "newpath %0.3f %0.3f %0.3f %0.3f %0.3f arc stroke\n",
+ D2I(x0), D2I(y0), D2I(r), angle1, angle0 );
+
+ if( drawCenter ) {
+ psPrintf(psFile,
+ "%0.3f %0.3f moveto %0.3f %0.3f lineto closepath stroke\n",
+ D2I(x0 - CENTERMARK_LENGTH / 2), D2I(y0), D2I(x0 + CENTERMARK_LENGTH / 2), D2I(y0) );
+ psPrintf(psFile,
+ "%0.3f %0.3f moveto %0.3f %0.3f lineto closepath stroke\n",
+ D2I(x0), D2I(y0 - CENTERMARK_LENGTH / 2), D2I(x0), D2I(y0 + CENTERMARK_LENGTH / 2) );
+
+ }
+}
+
+
+void psPrintFillRectangle(
+ wPos_t x0, wPos_t y0,
+ wPos_t x1, wPos_t y1,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ if (color == wDrawColorWhite)
+ return;
+ if (opts&wDrawOptTemp)
+ return;
+ psSetColor(color);
+ psPrintf(psFile,
+ "%0.3f %0.3f moveto %0.3f %0.3f lineto closepath fill\n",
+ D2I(x0), D2I(y0), D2I(x1), D2I(y1) );
+}
+
+
+void psPrintFillPolygon(
+ wPos_t p[][2],
+ int cnt,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ int inx;
+ if (color == wDrawColorWhite)
+ return;
+ if (opts&wDrawOptTemp)
+ return;
+ psSetColor(color);
+ psPrintf( psFile, "%0.3f %0.3f moveto ", D2I(p[0][0]), D2I(p[0][1]) );
+ for (inx=0; inx<cnt; inx++)
+ psPrintf( psFile, "%0.3f %0.3f lineto ", D2I(p[inx][0]), D2I(p[inx][1]) );
+ psPrintf( psFile, "closepath fill\n" );
+}
+
+
+void psPrintFillCircle(
+ wPos_t x0, wPos_t y0,
+ wPos_t r,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ if (color == wDrawColorWhite)
+ return;
+ if (opts&wDrawOptTemp)
+ return;
+ psSetColor(color);
+ psPrintf(psFile,
+ "newpath %0.3f %0.3f %0.3f 0.0 360.0 arc fill\n",
+ D2I(x0), D2I(y0), D2I(r) );
+}
+
+
+void psPrintString(
+ wPos_t x, wPos_t y,
+ double a,
+ char * s,
+ wFont_p fp,
+ double fs,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ char * cp;
+
+ fs = P2I(fs*fontSizeFactor);
+ if (fs < 0.05*72.0/1440.0)
+ return;
+#ifdef NOWHITE
+ if (color == wDrawColorWhite)
+ return;
+#endif
+ if (opts&wDrawOptTemp)
+ return;
+ psSetColor( color );
+ setLineType(currLineWidth, wDrawLineSolid, opts);
+ psPrintf(psFile,
+ "/%s findfont %0.3f scalefont setfont\n"
+ "gsave\n"
+ "%0.3f %0.3f translate %0.3f rotate 0 0 moveto\n(",
+ findPSFont(fp), fs, D2I(x), D2I(y), a );
+ addFontName(findPSFont(fp));
+ for (cp=s; *cp; cp++) {
+ if (*cp == '(' || *cp == ')')
+ psPrintf(psFile, "\\" );
+ psPrintf(psFile, "%c", *cp);
+ }
+ psPrintf(psFile, ") show\ngrestore\n" );
+}
+
+void wPrintClip( wPos_t x, wPos_t y, wPos_t w, wPos_t h )
+{
+ psPrintf( psFile, "\
+%0.3f %0.3f moveto \n\
+%0.3f %0.3f lineto \n\
+%0.3f %0.3f lineto \n\
+%0.3f %0.3f lineto \n\
+closepath clip newpath\n",
+ D2I(x), D2I(y),
+ D2I(x+w), D2I(y),
+ D2I(x+w), D2I(y+h),
+ D2I(x), D2I(y+h) );
+}
+
+/*****************************************************************************
+ *
+ * PAGE FUNCTIONS
+ *
+ */
+
+void wPrintGetPageSize(
+ double * w,
+ double * h )
+{
+ printInit();
+ if (printFormat == PRINT_LANDSCAPE) {
+ *w = papers[curPaper].h - tBorder - bBorder;
+ *h = papers[curPaper].w - lBorder - rBorder;
+ } else {
+ *w = papers[curPaper].w - lBorder - rBorder;
+ *h = papers[curPaper].h - tBorder - bBorder;
+ }
+}
+
+void wPrintGetPhysSize(
+ double * w,
+ double * h )
+{
+ printInit();
+ if (printFormat == PRINT_LANDSCAPE) {
+ *w = papers[curPaper].h;
+ *h = papers[curPaper].w;
+ } else {
+ *w = papers[curPaper].w;
+ *h = papers[curPaper].h;
+ }
+}
+
+
+static void printAbort( void * context )
+{
+ printContinue = FALSE;
+ wWinShow( printAbortW, FALSE );
+}
+
+/**
+ * Initialize new page.
+ *
+ * \return ???
+ */
+wDraw_p wPrintPageStart( void )
+{
+ char tmp[80];
+
+ if (psFile == NULL)
+ return NULL;
+
+ pageCount++;
+ psPrintf( psFile,
+ "%%%%Page: %d %d\n" \
+ "save\n" \
+ "gsave\n" \
+ "0 setlinewidth\n"\
+ "1 setlinecap\n",
+ pageCount,
+ (totalPageCount>0?totalPageCount:pageCount) );
+
+ if (printFormat == PRINT_LANDSCAPE) {
+ psPrintf(psFile, "%0.3f %0.3f translate -90 rotate\n", lBorder*PPI, (papers[curPaper].h-tBorder)*PPI);
+ } else {
+ psPrintf(psFile, "%0.3f %0.3f translate 0 rotate\n", lBorder*PPI, bBorder*PPI);
+ }
+
+ psPrintf( psFile, "%0.1f %0.1f scale\n", PPI, PPI );
+
+ psPrintf( psFile, "/Times-Bold findfont %0.3f scalefont setfont\n",
+ P2I(16) );
+ addFontName("Times-Bold");
+ sprintf( tmp, _("Page %d"), pageCount );
+ wMessageSetValue( printAbortM, tmp );
+ wFlush();
+
+ currLineWidth = 0;
+ return &psPrint_d;
+}
+
+/**
+ * End of page
+ *
+ * \param p IN ignored
+ * \return always printContinue
+ */
+
+
+wBool_t wPrintPageEnd( wDraw_p p )
+{
+ psPrintf( psFile,
+ "grestore\n" \
+ "restore\n" \
+ "showpage\n"\
+ "%%%%EndPage\n");
+
+ return printContinue;
+}
+
+/*****************************************************************************
+ *
+ * PRINT START/END
+ *
+ */
+
+/**
+ * Allow the user to enter a new file name and location for the file.
+ * Thanks to Andrew Krause's great book Foundations of GTK+ Development
+ * for this code snippet.
+ *
+ * \param junk IN ignored
+ */
+
+static void printFileNameSel( void * junk )
+{
+ GtkWidget *dialog;
+ gchar *filename;
+ gint result;
+
+ dialog = gtk_file_chooser_dialog_new (_("Print to file ..."), (GtkWindow *)printSetupW->gtkwin,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ result = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (result == GTK_RESPONSE_ACCEPT)
+ {
+ filename = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER ( dialog ));
+ if( filename ) {
+ sPrintFileName = malloc( strlen( filename ) + 1 );
+ if( sPrintFileName ) {
+ strcpy( sPrintFileName, filename );
+ }
+ else {
+ fputs( "Insufficient memory for printing to file\n", stderr );
+ abort();
+ }
+ g_free( filename );
+ }
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+
+/*
+ * open the printer output stream. In case print to file is selected, the filename for
+ * the print out is fetched from the user and the file opened.
+ *
+ * \return the printer stream
+ */
+
+wPrinterStream_p wPrinterOpen( void )
+{
+ char * fn;
+ char sPrintCmdName[80];
+ char tmp[80+8];
+ FILE * f;
+ wIndex_t cmdOrFile;
+ wPrinterStream_p p;
+
+ printInit();
+ pageCount = 0;
+ f = NULL;
+ curPsFont = NULL;
+ if (curPrinter == 0 ) {
+
+ printFileNameSel( NULL );
+
+ // did the user cancel the file dialog? If yes, cancel operation
+ if( !sPrintFileName ) {
+ return( NULL );
+ }
+ if ( sPrintFileName[0] == '\0' ) {
+ wNoticeEx( NT_ERROR, _("No file name specified"), _("Ok"), NULL );
+ return NULL;
+ }
+ if ( access(sPrintFileName, F_OK ) == 0 ) {
+ sprintf( tmp, _("%s exists"), sPrintFileName );
+ if (!wNoticeEx( NT_INFORMATION, tmp, _("Overwrite"), _("Cancel") ))
+ return NULL;
+ }
+ f = fopen( sPrintFileName, "w" );
+ if (f == NULL) {
+ strcat( sPrintFileName, _(": cannot open") );
+ wNoticeEx( NT_ERROR, sPrintFileName, _("Ok"), NULL );
+ return NULL;
+ }
+ fn = sPrintFileName;
+ cmdOrFile = PRINT_FILE;
+ } else {
+ sprintf( sPrintCmdName, printers(curPrinter).cmd, printers(curPrinter).name );
+ f = popen( sPrintCmdName, "w" );
+ fn = sPrintCmdName;
+ cmdOrFile = PRINT_COMMAND;
+ }
+ if (f == NULL) {
+ strcat( sPrintFileName, _(": cannot open") );
+ wNoticeEx( NT_ERROR, sPrintFileName, _("Ok"), NULL );
+ return NULL;
+ }
+ p = (wPrinterStream_p)malloc( sizeof *p );
+ p->f = f;
+ p->cmdOrFile = cmdOrFile;
+ return p;
+}
+
+
+void wPrinterWrite( wPrinterStream_p p, char * buff, int siz )
+{
+ fwrite( buff, 1, siz, p->f );
+}
+
+void wPrinterClose( wPrinterStream_p p )
+{
+ if (p->cmdOrFile == PRINT_FILE)
+ fclose( p->f );
+ else
+ pclose( p->f );
+
+ // free the filename again
+ if( sPrintFileName ) {
+ free( sPrintFileName );
+ sPrintFileName = NULL;
+ }
+}
+
+/**
+ * Start a new Postscript document
+ *
+ * Opens the output file and emits the Adobe DSC Prolog comments,
+ * etc. Note that the 3.0 in "PS-Adobe-3.0" refers to the
+ * version of the Document Structuring Conventions Specification,
+ * not to the Postscript language level.
+ *
+ * \param title IN title of document ( name of layout )
+ * \param fTotalPageCount IN number of pages to print
+ * \param copiesP OUT ???
+ * \return TRUE if successful
+ */
+
+wBool_t wPrintDocStart( const char * title, int fTotalPageCount, int * copiesP )
+{
+ char tmp[80];
+ pageCount = 0;
+ totalPageCount = fTotalPageCount;
+ psFile = NULL;
+ psFileStream = wPrinterOpen();
+ if (psFileStream == NULL)
+ return FALSE;
+ psFile = psFileStream->f;
+
+ /* Initialize the list of fonts used */
+ fontsUsedInit(); /* in case a document had been
+ produced earlier */
+
+ psPrintf( psFile,
+ "%%!PS-Adobe-3.0\n\
+%%%%DocumentFonts: (atend)\n\
+%%%%Title: %s\n\
+%%%%Creator: XTrackCAD\n\
+%%%%Pages: (atend)\n\
+%%%%BoundingBox: %ld %ld %ld %ld\n\
+%%%%EndComments\n\n\
+%%%%Prolog\n\
+/mp_stm usertime def\n\
+/mp_pgc statusdict begin pagecount end def\n\
+statusdict begin /jobname (<stdin>) def end\n\
+%%%%EndProlog\n", \
+ title,
+ (long)floor(margins(curMargin).l*72),
+ (long)floor(margins(curMargin).b*72),
+ (long)floor((papers[curPaper].w-margins(curMargin).r)*72),
+ (long)floor((papers[curPaper].h-margins(curMargin).t)*72) );
+
+ printContinue = TRUE;
+ sprintf( tmp, ("Now printing %s"), title );
+ wMessageSetValue( printAbortT, tmp );
+ wMessageSetValue( printAbortM, _("Page 1") );
+ pageCount = 0;
+ wWinShow( printAbortW, TRUE );
+ if (copiesP)
+ *copiesP = 1;
+ return TRUE;
+}
+
+/**
+ * Outputs the Adobe Document Structure Comments.
+ * These are needed at the
+ * end of a Postscript document destined for modern (2012) print
+ * spoolers. E.g. CUPS
+ */
+
+void wPrintDocEnd( void )
+{
+ struct list_node *p;
+ int i;
+ if (psFile == NULL)
+ return;
+
+ psPrintf( psFile,
+ "%%%%Trailer\n%%%%Pages: %d\n",
+ pageCount );
+
+ /* Postscript lines are <255 chars so print fonts list 4
+ per line
+ */
+ psPrintf( psFile, "%%%%DocumentFonts: " );
+ p = fontsUsed;
+ i = 0;
+ while ((p=fontsUsedPop()) != NULL) {
+ if ((i % 4) == 0 ) psPrintf( psFile, "\n%%%%+ ");
+ psPrintf( psFile, " %s", p->data);
+ free(p->data);
+ free(p);
+ i++;
+ }
+ psPrintf( psFile, "\n");
+
+ psPrintf( psFile, "%%%%EOF\n");
+ /* Reset the fonts list to empty for the next document.
+ */
+ fontsUsedInit();
+
+ wPrinterClose( psFileStream );
+ wWinShow( printAbortW, FALSE );
+}
+
+
+wBool_t wPrintQuit( void )
+{
+ return FALSE;
+}
+
+
+static void pLine( double x0, double y0, double x1, double y1 )
+{
+ psPrintf( psFile, "%0.3f %0.3f moveto %0.3f %0.3f lineto stroke\n",
+ x0, y0, x1, y1 );
+}
+
+/**
+ * Generate a test page that helps setting up printer margins.
+ */
+
+static void pTestPage( void )
+{
+ double w, h;
+ long oldPrinter;
+ int i, j, k, run;
+ double x0, x1, y0, y1;
+ const char * psFont, * xFont;
+ long curMargin0;
+
+ oldPrinter = curPrinter;
+ curPrinter = newPPrinter;
+ curMargin0 = curMargin;
+ curMargin = 0;
+ wPrintDocStart( _("Printer Margin Test Page"), 1, NULL );
+ wPrintPageStart();
+ curMargin = curMargin0;
+ w = papers[curPaper].w;
+ h = papers[curPaper].h;
+ if ( psFile == NULL )
+ return;
+
+#define MAXIMUM (100)
+
+ psPrintf( psFile, "/Times-Roman findfont 0.06 scalefont setfont\n" );
+ addFontName("Times-Roman");
+ for ( i=5; i<=MAXIMUM; i+=5 ) {
+ x0 = ((double)i)/100;
+ pLine( 0.5, x0, w-0.5, x0 );
+ pLine( 0.5, h-x0, w-0.5, h-x0 );
+ pLine( x0, 0.5, x0, h-0.5 );
+ pLine( w-x0, 0.5, w-x0, h-0.5 );
+
+ psPrintf( psFile, "%0.3f %0.3f moveto (%0.2f) show\n",
+ 1.625 + x0*5 - 0.05, 0.2+MAXIMUM/100.0, x0 );
+ pLine( 1.625 + x0*5, (0.2+MAXIMUM/100.0), 1.625 + x0*5, x0 );
+ psPrintf( psFile, "%0.3f %0.3f moveto (%0.2f) show\n",
+ 1.625 + x0*5 - 0.05, h-(0.2+MAXIMUM/100.0)-0.05, x0 );
+ pLine( 1.625 + x0*5, h-(0.2+MAXIMUM/100.0), 1.625 + x0*5, h-x0 );
+
+ psPrintf( psFile, "%0.3f %0.3f moveto (%0.2f) show\n",
+ (0.2+MAXIMUM/100.0), 1.625 + x0*5-0.020, x0 );
+ pLine( (0.2+MAXIMUM/100.0), 1.625 + x0*5, x0, 1.625 + x0*5 );
+ psPrintf( psFile, "%0.3f %0.3f moveto (%0.2f) show\n",
+ w-(0.2+MAXIMUM/100.0)-0.10, 1.625 + x0*5-0.020, x0 );
+ pLine( w-(0.2+MAXIMUM/100.0), 1.625 + x0*5, w-x0, 1.625 + x0*5 );
+ }
+
+ psPrintf( psFile, "/Times-Bold findfont 0.20 scalefont setfont\n" );
+ addFontName("Times-Bold");
+ psPrintf( psFile, "%0.3f %0.3f moveto (%s) show\n", 2.0, h-2.0, "Printer Margin Setup" );
+ psPrintf( psFile, "/Times-Roman findfont 0.12 scalefont setfont\n" );
+ addFontName("Times-Roman");
+ psPrintf( psFile, "%0.3f %0.3f moveto (%s) show\n", 2.0, h-2.15,
+ "Enter the position of the first visible line for each margin on the Printer Setup dialog");
+ if ( curMargin < margins_da.cnt )
+ psPrintf( psFile, "%0.3f %0.3f moveto ("
+ "Current margins for the %s printer are: Top: %0.3f, Left: %0.3f, Right: %0.3f, Bottom: %0.3f"
+ ") show\n", 2.0, h-2.30,
+ margins(curMargin).name, margins(curMargin).t, margins(curMargin).l, margins(curMargin).r, margins(curMargin).b );
+
+
+ psPrintf( psFile, "/Times-Bold findfont 0.20 scalefont setfont\n" );
+ addFontName("Times-Bold");
+ psPrintf( psFile, "%0.3f %0.3f moveto (%s) show\n", 2.0, h-3.0, "Font Map" );
+ for (i=j=0; 0.2*j < h-5.0 && (psFont = wPrefGetSectionItem( WFONT, &i, &xFont )) != NULL; j++ ) {
+ if ( psFont[0] == '\0' ) continue;
+ psPrintf( psFile, "/Times-Roman findfont 0.12 scalefont setfont\n" );
+ addFontName("Times-Roman");
+ psPrintf( psFile, "%0.3f %0.3f moveto (%s -> %s) show\n", 2.0, h-3.15-0.15*j, xFont, psFont );
+ psPrintf( psFile, "/%s findfont 0.12 scalefont setfont\n", psFont );
+ addFontName(psFont);
+ psPrintf( psFile, "%0.3f %0.3f moveto (%s) show\n", 5.5, h-3.15-0.15*j, "ABCD wxyz 0123 -+$!" );
+ }
+ x0 = 0.5;
+ run = TRUE;
+ i = 0;
+ while (run) {
+ x1 = x0 + 0.25;
+ if (x1 >= w-0.5) {
+ x1 = w-0.5;
+ run = FALSE;
+ }
+ for ( j = 1; j<5; j++ ) {
+ y0 = ((double)(i+j))/100;
+ for (k=0; k<MAXIMUM/25; k++) {
+ pLine( x0, y0+k*0.25, x1, y0+k*0.25 );
+ pLine( x0, h-y0-k*0.25, x1, h-y0-k*0.25 );
+ }
+ }
+ x0 += 0.25;
+ i += 5;
+ if (i >= 25)
+ i = 0;
+ }
+
+ y0 = 0.5;
+ run = TRUE;
+ i = 0;
+ while (run) {
+ y1 = y0 + 0.25;
+ if (y1 >= h-0.5) {
+ y1 = h-0.5;
+ run = FALSE;
+ }
+ for ( j = 1; j<5; j++ ) {
+ x0 = ((double)(i+j))/100;
+ for (k=0; k<MAXIMUM/25; k++) {
+ pLine( x0+k*0.25, y0, x0+k*0.25, y1 );
+ pLine( w-x0-k*0.25, y0, w-x0-k*0.25, y1 );
+ }
+ }
+ y0 += 0.25;
+ i += 5;
+ if (i >= 25)
+ i = 0;
+ }
+
+ /* psPrintf( psFile, "showpage\n"); */
+ wPrintPageEnd(NULL);
+ wPrintDocEnd();
+ curPrinter = oldPrinter;
+}
+
+
+#ifdef LATER
+static void newPrinter( void * context )
+{
+ wStringSetValue( addPrinterN, "" );
+ wStringSetValue( addPrinterC, "" );
+ addPrinterName[0] = 0;
+ addPrinterCommand[0] = 0;
+ wWinShow( addPrinterW, TRUE );
+}
+
+
+static void addPrinterOk( const char * str, void * context )
+{
+ char tmp[80];
+ if (strlen(addPrinterName) == 0 || strlen(addPrinterCommand) == 0) {
+ wNotice( _("Enter both printer name and command"), _("Ok"), NULL );
+ return;
+ }
+ if (printerDefine)
+ printerDefine( addPrinterName, addPrinterCommand );
+ else
+ wNotice( _("Can not save New Printer definition"), _("Ok"), NULL );
+ sprintf( tmp, "%s=%s", addPrinterName, addPrinterCommand );
+ wPrintNewPrinter( tmp );
+}
+
+
+static void newMargin( void * context )
+{
+ wStringSetValue( addMarginN, "" );
+ addMarginName[0] = 0;
+ wWinShow( addMarginW, TRUE );
+ gtkSetReadonly((wControl_p)optTopMargin,FALSE);
+ gtkSetReadonly((wControl_p)optBottomMargin,FALSE);
+ gtkSetReadonly((wControl_p)optLeftMargin,FALSE);
+ gtkSetReadonly((wControl_p)optRightMargin,FALSE);
+}
+
+
+static void addMarginOk( const char * str, void * context )
+{
+ margins_t * m;
+ if (strlen(addMarginName) == 0) {
+ wNotice( _("Enter printer name"), _("Ok"), NULL );
+ return;
+ }
+ if (marginDefine)
+ marginDefine( addMarginName, tBorder, bBorder, rBorder, lBorder );
+ else
+ wNotice( _("Can not save New Margin definition"), _("Ok"), NULL );
+ DYNARR_APPEND( margins_t, margins_da, 10 );
+ m = &margins(margins_da.cnt-1);
+ m->name = strdup( addMarginName );
+ m->t = tBorder;
+ m->b = bBorder;
+ m->r = rBorder;
+ m->l = lBorder;
+ wListAddValue( optMarginB, addMarginName, NULL, NULL );
+ gtkSetReadonly((wControl_p)optTopMargin,TRUE);
+ gtkSetReadonly((wControl_p)optBottomMargin,TRUE);
+ gtkSetReadonly((wControl_p)optLeftMargin,TRUE);
+ gtkSetReadonly((wControl_p)optRightMargin,TRUE);
+}
+#endif
+
+
+static wLines_t lines[] = {
+ { 1, 25, 11, 95, 11 },
+ { 1, 95, 11, 95, 111 },
+ { 1, 95, 111, 25, 111 },
+ { 1, 25, 111, 25, 11 }};
+#ifdef LATER
+ { 1, 97, 10, 125, 10 },
+ { 1, 160, 10, 177, 10 },
+ { 1, 97, 10, 97, 50 },
+ { 1, 97, 67, 97, 110 },
+ { 1, 177, 10, 177, 50 },
+ { 1, 177, 67, 177, 110 },
+ { 1, 97, 110, 125, 110 },
+ { 1, 160, 110, 177, 110 } };
+#endif
+
+static const char * printFmtLabels[] = { N_("Portrait"), N_("Landscape"), NULL };
+
+static struct {
+ const char * xfontname, * psfontname;
+ } fontmap[] = {
+ { "times-medium-r", "Times-Roman" },
+ { "times-medium-i", "Times-Italic" },
+ { "times-bold-r", "Times-Bold" },
+ { "times-bold-i", "Times-BoldItalic" },
+ { "helvetica-medium-r", "Helvetica" },
+ { "helvetica-medium-o", "Helvetica-Oblique" },
+ { "helvetica-bold-r", "Helvetica-Bold" },
+ { "helvetica-bold-o", "Helvetica-BoldOblique" },
+ { "courier-medium-r", "Courier" },
+ { "courier-medium-o", "Courier-Oblique" },
+ { "courier-medium-i", "Courier-Oblique" },
+ { "courier-bold-r", "Courier-Bold" },
+ { "courier-bold-o", "Courier-BoldOblique" },
+ { "courier-bold-i", "Courier-BoldOblique" },
+ { "avantgarde-book-r", "AvantGarde-Book" },
+ { "avantgarde-book-o", "AvantGarde-BookOblique" },
+ { "avantgarde-demi-r", "AvantGarde-Demi" },
+ { "avantgarde-demi-o", "AvantGarde-DemiOblique" },
+ { "palatino-medium-r", "Palatino-Roman" },
+ { "palatino-medium-i", "Palatino-Italic" },
+ { "palatino-bold-r", "Palatino-Bold" },
+ { "palatino-bold-i", "Palatino-BoldItalic" },
+ { "new century schoolbook-medium-r", "NewCenturySchlbk-Roman" },
+ { "new century schoolbook-medium-i", "NewCenturySchlbk-Italic" },
+ { "new century schoolbook-bold-r", "NewCenturySchlbk-Bold" },
+ { "new century schoolbook-bold-i", "NewCenturySchlbk-BoldItalic" },
+ { "zapfchancery-medium-i", "ZapfChancery-MediumItalic" } };
+
+static struct {
+ const char * name, * value;
+ } pagemargins [] = {
+ { "None", "0.00 0.00 0.00 0.00" },
+ { "BJC-600", "0.10 0.44 0.38 0.13" },
+ { "DeskJet", "0.167 0.50 0.25 0.25" },
+ { "PaintJet", "0.167 0.167 0.167 0.167" },
+ { "DJ505", "0.25 0.668 0.125 0.125" },
+ { "DJ560C", "0.37 0.46 0.25 0.25" },
+ { "LaserJet", "0.43 0.21 0.43 0.28" } };
+
+
+static void doSetOptXFont(
+ wIndex_t inx,
+ const char * xFont,
+ wIndex_t inx2,
+ void * itemData,
+ void * listData )
+{
+ const char * cp;
+ optXFont = xFont;
+ cp = wPrefGetString( WFONT, xFont );
+ if ( !cp )
+ cp = "";
+ wStringSetValue( optPSFontS, cp );
+}
+
+
+static void doSetOptPSFont(
+ const char * psFont,
+ void * data )
+{
+ if ( optXFont &&
+ psFont[0] )
+ wPrefSetString( WFONT, optXFont, psFont );
+}
+
+
+static void printInit( void )
+{
+ wIndex_t i;
+ wPos_t x, y;
+ static wBool_t printInitted = FALSE;
+ const char * cp, * cq;
+ char num[10];
+
+ if (printInitted)
+ return;
+
+ printInitted = TRUE;
+ prefName = wPrefGetString( "printer", "name" );
+ prefPaper = wPrefGetString( "printer", "paper" );
+ prefMargin = wPrefGetString( "printer", "margin" );
+ prefFormat = wPrefGetString( "printer", "format" );
+ if (prefFormat && strcasecmp(prefFormat, "landscape") == 0)
+ printFormat = PRINT_LANDSCAPE;
+ else
+ printFormat = PRINT_PORTRAIT;
+ wPrefGetFloat( WPRINTFONT, "factor", &fontSizeFactor, 1.0 );
+ if ( fontSizeFactor < 0.5 || fontSizeFactor > 2.0 ) {
+ fontSizeFactor = 1.0;
+ wPrefSetFloat( WPRINTFONT, "factor", fontSizeFactor );
+ }
+
+ x = wLabelWidth( _("Paper Size") )+4;
+ printSetupW = wWinPopupCreate( NULL, 4, 4, "printSetupW", _("Print Setup"), "xvprintsetup", F_AUTOSIZE|F_RECALLPOS, NULL, NULL );
+ optPrinterB = wDropListCreate( printSetupW, x, -4, "printSetupPrinter", _("Printer"), 0, 4, 100, &newPPrinter, NULL, NULL );
+#ifdef LATER
+ wButtonCreate( printSetupW, -10, 2, "printSetupPrinter", _("New"), 0, 0, newPrinter, NULL );
+#endif
+ optPaperSizeB = wDropListCreate( printSetupW, x, -4, "printSetupPaper", _("Paper Size"), 0, 4, 100, &newPPaper, NULL, NULL );
+ y = wControlGetPosY( (wControl_p)optPaperSizeB ) + wControlGetHeight( (wControl_p)optPaperSizeB ) + 10;
+ for ( i=0; i<sizeof lines / sizeof lines[0]; i++ ) {
+ lines[i].x0 += x;
+ lines[i].x1 += x;
+ lines[i].y0 += y;
+ lines[i].y1 += y;
+ }
+ wLineCreate( printSetupW, NULL, sizeof lines / sizeof lines[0], lines );
+ optTopMargin = wFloatCreate( printSetupW, x+35, y, "printSetupMargin", NULL, 0, 50, 0.0, 1.0, &tBorder, (wFloatCallBack_p)doChangeMargin, NULL );
+ optLeftMargin = wFloatCreate( printSetupW, x, y+50, "printSetupMargin", _("Margin"), 0, 50, 0.0, 1.0, &lBorder, (wFloatCallBack_p)doChangeMargin, NULL );
+ optRightMargin = wFloatCreate( printSetupW, x+70, y+50, "printSetupMargin", NULL, 0, 50, 0.0, 1.0, &rBorder, (wFloatCallBack_p)doChangeMargin, NULL );
+ optBottomMargin = wFloatCreate( printSetupW, x+35, y+100, "printSetupMargin", NULL, 0, 50, 0.0, 1.0, &bBorder, (wFloatCallBack_p)doChangeMargin, NULL );
+ optMarginB = wDropListCreate( printSetupW, x, -5, "printSetupMargin", NULL, BL_EDITABLE, 4, 100, NULL, doMarginSel, NULL );
+ optMarginDelB = wButtonCreate( printSetupW, wControlGetPosX((wControl_p)optMarginB)+wControlGetWidth((wControl_p)optMarginB)+5, wControlGetPosY((wControl_p)optMarginB), "printSetupMarginDelete", "Delete", 0, 0, (wButtonCallBack_p)doMarginDelete, NULL );
+#ifdef LATER
+ wButtonCreate( printSetupW, -10, wControlGetPosY((wControl_p)optMarginB), "printSetupMargin", _("New"), 0, 0, newMargin, NULL );
+#endif
+ optFormat = wRadioCreate( printSetupW, x, -5, "printSetupFormat", _("Format"), BC_HORZ,
+ printFmtLabels, &printFormat, NULL, NULL );
+ optXFontL = wDropListCreate( printSetupW, x, -6, "printSetupXFont", _("X Font"), 0, 4, 200, &optXFontX, doSetOptXFont, NULL );
+ optPSFontS = wStringCreate( printSetupW, x, -4, "printSetupPSFont", _("PS Font"), 0, 200, optPSFont, 0, doSetOptPSFont, NULL );
+ optFontSizeFactor = wFloatCreate( printSetupW, x, -4, "printSetupFontSizeFactor", _("Factor"), 0, 50, 0.5, 2.0, &fontSizeFactor, (wFloatCallBack_p)NULL, NULL );
+ y = wControlGetPosY( (wControl_p)optFontSizeFactor ) + wControlGetHeight( (wControl_p)optFontSizeFactor ) + 10;
+ x = wControlGetPosX( (wControl_p)optPrinterB ) + wControlGetWidth( (wControl_p)optPrinterB ) + 10;
+ wButtonCreate( printSetupW, x, 4, "printSetupOk", _("Ok"), 0, 0, (wButtonCallBack_p)pSetupOk, NULL );
+ wButtonCreate( printSetupW, x, -4, "printSetupCancel", _("Cancel"), 0, 0, (wButtonCallBack_p)pSetupCancel, NULL );
+ wButtonCreate( printSetupW, x, -14, "printSetupTest", _("Print Test Page"), 0, 0, (wButtonCallBack_p)pTestPage, NULL );
+
+#ifdef LATER
+ addPrinterW = wWinPopupCreate( printSetupW, 2, 2, "printSetupPrinter", _("Add Printer"), "xvaddprinter", F_AUTOSIZE|F_RECALLPOS, NULL, NULL );
+ addPrinterN = wStringCreate( addPrinterW, 100, -3, "printSetupPrinter",
+ _("Name: "), 0, 150, addPrinterName, sizeof addPrinterName,
+ addPrinterOk, NULL );
+ addPrinterC = wStringCreate( addPrinterW, 100, -3, "printSetupPrinter",
+ _("Command: "), 0, 150, addPrinterCommand, sizeof addPrinterCommand,
+ addPrinterOk, NULL );
+
+ addMarginW = wWinPopupCreate( printSetupW, 2, 2, "printSetupMargin", _("Add Margin"), "xvaddmargin", F_AUTOSIZE|F_RECALLPOS, NULL, NULL );
+ addMarginN = wStringCreate( addMarginW, 100, -3, "printSetupMargin",
+ _("Name: "), 0, 150, addMarginName, sizeof addMarginName,
+ addMarginOk, NULL );
+#endif
+
+ printFileW = wWinPopupCreate( printSetupW, 2, 2, "printFileNameW", _("Print To File"), "xvprinttofile", F_BLOCK|F_AUTOSIZE|F_RECALLPOS, NULL, NULL );
+ wStringCreate( printFileW, 100, 3, "printFileName",
+ _("File Name? "), 0, 150, sPrintFileName, sizeof sPrintFileName,
+ NULL, NULL );
+ wButtonCreate( printFileW, -4, 3, "printFileNameOk", _("Ok"), BB_DEFAULT, 0, printFileNameSel, NULL );
+
+ newFontAliasW = wWinPopupCreate( printSetupW, 2, 2, "printFontAliasW", _("Font Alias"), "xvfontalias", F_BLOCK|F_AUTOSIZE|F_RECALLPOS, NULL, NULL );
+ wMessageCreate( newFontAliasW, 0, 0, NULL, 200, _("Enter a post-script font name for:") );
+ newFontAliasXFntB = wMessageCreate( newFontAliasW, 0, -3, NULL, 200, "" );
+ wStringCreate( newFontAliasW, 0, -3, "printFontAlias", NULL, 0, 200, NULL, 0, newFontAliasSel, NULL );
+
+ for (i=0; papers[i].name; i++ ) {
+ wListAddValue( optPaperSizeB, papers[i].name, NULL, (void*)(intptr_t)i );
+ if ( prefPaper && strcasecmp( prefPaper, papers[i].name ) == 0 ) {
+ curPaper = i;
+ wListSetIndex( optPaperSizeB, i );
+ }
+ }
+
+ printAbortW = wWinPopupCreate( printSetupW, 2, 2, "printAbortW", _("Printing"), "xvprintabort", F_AUTOSIZE|F_RECALLPOS, NULL, NULL );
+ printAbortT = wMessageCreate( printAbortW, 0, 0, "printAbortW", 200, _("Now printing") );
+ printAbortM = wMessageCreate( printAbortW, 0, -4, "printAbortW", 200, NULL );
+ wButtonCreate( printAbortW, 0, 80, "printAbortW", _("Abort Print"), 0, 0, printAbort, NULL );
+
+ for (i=0;i<sizeof fontmap/sizeof fontmap[0]; i++) {
+ cp = wPrefGetString( WFONT, fontmap[i].xfontname );
+ if (!cp)
+ wPrefSetString( WFONT, fontmap[i].xfontname, fontmap[i].psfontname );
+ }
+
+ cp = wPrefGetString( WPRINTER, "1" );
+ if (!cp)
+ wPrefSetString( WPRINTER, "1", "lp=lpr -P%s" );
+ wPrintNewPrinter( "FILE" );
+ for (i=1; ;i++) {
+ sprintf( num, "%d", i );
+ cp = wPrefGetString( WPRINTER, num );
+ if (!cp)
+ break;
+ wPrintNewPrinter(cp);
+ }
+
+ for (i=0;i<sizeof pagemargins/sizeof pagemargins[0]; i++) {
+ cp = wPrefGetString( WMARGIN, pagemargins[i].name );
+ if (!cp)
+ wPrefSetString( WMARGIN, pagemargins[i].name, pagemargins[i].value );
+ sprintf( num, "%d", i );
+ wPrefSetString( WMARGINMAP, num, pagemargins[i].name );
+ }
+ for (i=0; (cq = wPrefGetSectionItem( WMARGIN, &i, &cp )); ) {
+ wPrintNewMargin(cp, cq);
+ }
+
+ for ( i=0, optXFont=NULL; wPrefGetSectionItem( WFONT, &i, &cp ); ) {
+ if ( optXFont == NULL )
+ optXFont = cp;
+ wListAddValue( optXFontL, cp, NULL, NULL );
+ }
+ wListSetIndex( optXFontL, 0 );
+ if ( optXFont ) {
+ cp = wPrefGetString( WFONT, optXFont );
+ wStringSetValue( optPSFontS, cp );
+ }
+
+}
+
+
+wBool_t wPrintInit( void )
+{
+ return TRUE;
+}
+
+/*****************************************************************************
+ *
+ * TEST
+ *
+ */
+
+#ifdef TEST
+
+void main ( INT_T argc, char * argv[] )
+{
+ if (argc != 7) {
+ fprintf( stderr, "%s <L|P> <origX> <origY> <roomSizeX> <roomSizeY>\n", argv[0] );
+ exit(1);
+ }
+ argv++;
+ printFormat = (*(*argv++)=='L')?PRINT_LANDSCAPE:PRINT_PORTRAIT;
+ printDraw_d.orig.x = atof(*argv++);
+ printDraw_d.orig.y = atof(*argv++);
+ printRoomSize.x = atof(*argv++);
+ printRoomSize.y = atof(*argv++);
+ fprintf( stderr, "Fmt=%c, orig=(%0.3f %0.3f) RS=(%0.3f %0.3f)\n",
+ (printFormat==PRINT_LANDSCAPE)?'L':'P',
+ printDraw_d.orig.x, printDraw_d.orig.y,
+ printRoomSize.x, printRoomSize.y );
+ wPrintGetPageSize(PRINT_GAUDY, printFormat);
+ fprintf( stderr, "PageSize= (%0.3f %0.3f)\n", printDraw_d.size.x, printDraw_d.size.y );
+
+ wPrintDocStart( PRINT_GAUDY );
+ wPrintPage( PRINT_GAUDY, 0, 0 );
+ wPrintDocEnd( );
+}
+
+#endif
diff --git a/app/wlib/gtklib/square10.bmp b/app/wlib/gtklib/square10.bmp
new file mode 100644
index 0000000..b2eee6e
--- /dev/null
+++ b/app/wlib/gtklib/square10.bmp
@@ -0,0 +1,8 @@
+#define square10_width 14
+#define square10_height 14
+// Changed to eliminate compile-time warning
+//static unsigned char square10_bits[] = {
+static 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};
diff --git a/app/wlib/gtklib/uthash.h b/app/wlib/gtklib/uthash.h
new file mode 100644
index 0000000..39fd891
--- /dev/null
+++ b/app/wlib/gtklib/uthash.h
@@ -0,0 +1,960 @@
+/*
+Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#include <string.h> /* memcmp,strlen */
+#include <stddef.h> /* ptrdiff_t */
+#include <stdlib.h> /* exit() */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#if defined(_MSC_VER) /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#else /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ char **_da_dst = (char**)(&(dst)); \
+ *_da_dst = (char*)(src); \
+} while(0)
+#else
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ (dst) = DECLTYPE(dst)(src); \
+} while(0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
+#if defined (_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1600
+#include <stdint.h>
+#elif defined(__WATCOMC__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+#else
+#include <stdint.h>
+#endif
+
+#define UTHASH_VERSION 1.9.9
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
+#endif
+#ifndef uthash_malloc
+#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) free(ptr) /* free fcn */
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl) /* can be defined to log expands */
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhe */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+
+#define HASH_FIND(hh,head,keyptr,keylen,out) \
+do { \
+ out=NULL; \
+ if (head) { \
+ unsigned _hf_bkt,_hf_hashv; \
+ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
+ if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
+ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
+ keyptr,keylen,out); \
+ } \
+ } \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+#define HASH_BLOOM_MAKE(tbl) \
+do { \
+ (tbl)->bloom_nbits = HASH_BLOOM; \
+ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
+ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
+ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
+ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
+} while (0)
+
+#define HASH_BLOOM_FREE(tbl) \
+do { \
+ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+} while (0)
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+
+#define HASH_BLOOM_ADD(tbl,hashv) \
+ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#define HASH_BLOOM_TEST(tbl,hashv) \
+ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0
+#endif
+
+#define HASH_MAKE_TABLE(hh,head) \
+do { \
+ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
+ sizeof(UT_hash_table)); \
+ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
+ (head)->hh.tbl->tail = &((head)->hh); \
+ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
+ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
+ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
+ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl->buckets, 0, \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_MAKE((head)->hh.tbl); \
+ (head)->hh.tbl->signature = HASH_SIGNATURE; \
+} while(0)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
+ HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
+do { \
+ replaced=NULL; \
+ HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \
+ if (replaced!=NULL) { \
+ HASH_DELETE(hh,head,replaced); \
+ } \
+ HASH_ADD(hh,head,fieldname,keylen_in,add); \
+} while(0)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
+do { \
+ unsigned _ha_bkt; \
+ (add)->hh.next = NULL; \
+ (add)->hh.key = (char*)(keyptr); \
+ (add)->hh.keylen = (unsigned)(keylen_in); \
+ if (!(head)) { \
+ head = (add); \
+ (head)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh,head); \
+ } else { \
+ (head)->hh.tbl->tail->next = (add); \
+ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
+ (head)->hh.tbl->tail = &((add)->hh); \
+ } \
+ (head)->hh.tbl->num_items++; \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
+ (add)->hh.hashv, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
+ HASH_FSCK(hh,head); \
+} while(0)
+
+#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
+do { \
+ bkt = ((hashv) & ((num_bkts) - 1)); \
+} while(0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ * HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr) \
+do { \
+ struct UT_hash_handle *_hd_hh_del; \
+ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ head = NULL; \
+ } else { \
+ unsigned _hd_bkt; \
+ _hd_hh_del = &((delptr)->hh); \
+ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
+ (head)->hh.tbl->tail = \
+ (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho); \
+ } \
+ if ((delptr)->hh.prev) { \
+ ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \
+ } else { \
+ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
+ } \
+ if (_hd_hh_del->next) { \
+ ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \
+ (head)->hh.tbl->hho))->prev = \
+ _hd_hh_del->prev; \
+ } \
+ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
+ (head)->hh.tbl->num_items--; \
+ } \
+ HASH_FSCK(hh,head); \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out) \
+ HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add) \
+ HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add)
+#define HASH_REPLACE_STR(head,strfield,add,replaced) \
+ HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced)
+#define HASH_FIND_INT(head,findint,out) \
+ HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add) \
+ HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced) \
+ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out) \
+ HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add) \
+ HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \
+ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr) \
+ HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head) \
+do { \
+ struct UT_hash_handle *_thh; \
+ if (head) { \
+ unsigned _bkt_i; \
+ unsigned _count; \
+ char *_prev; \
+ _count = 0; \
+ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
+ unsigned _bkt_count = 0; \
+ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
+ _prev = NULL; \
+ while (_thh) { \
+ if (_prev != (char*)(_thh->hh_prev)) { \
+ HASH_OOPS("invalid hh_prev %p, actual %p\n", \
+ _thh->hh_prev, _prev ); \
+ } \
+ _bkt_count++; \
+ _prev = (char*)(_thh); \
+ _thh = _thh->hh_next; \
+ } \
+ _count += _bkt_count; \
+ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
+ HASH_OOPS("invalid bucket count %u, actual %u\n", \
+ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
+ } \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid hh item count %u, actual %u\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ /* traverse hh in app order; check next/prev integrity, count */ \
+ _count = 0; \
+ _prev = NULL; \
+ _thh = &(head)->hh; \
+ while (_thh) { \
+ _count++; \
+ if (_prev !=(char*)(_thh->prev)) { \
+ HASH_OOPS("invalid prev %p, actual %p\n", \
+ _thh->prev, _prev ); \
+ } \
+ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
+ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
+ (head)->hh.tbl->hho) : NULL ); \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid app item count %u, actual %u\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ } \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
+do { \
+ unsigned _klen = fieldlen; \
+ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
+ write(HASH_EMIT_KEYS, keyptr, fieldlen); \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
+#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hb_keylen=keylen; \
+ const char *_hb_key=(const char*)(key); \
+ (hashv) = 0; \
+ while (_hb_keylen--) { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; } \
+ bkt = (hashv) & (num_bkts-1); \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _sx_i; \
+ const char *_hs_key=(const char*)(key); \
+ hashv = 0; \
+ for(_sx_i=0; _sx_i < keylen; _sx_i++) \
+ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
+ bkt = hashv & (num_bkts-1); \
+} while (0)
+/* FNV-1a variation */
+#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _fn_i; \
+ const char *_hf_key=(const char*)(key); \
+ hashv = 2166136261UL; \
+ for(_fn_i=0; _fn_i < keylen; _fn_i++) { \
+ hashv = hashv ^ _hf_key[_fn_i]; \
+ hashv = hashv * 16777619; \
+ } \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _ho_i; \
+ const char *_ho_key=(const char*)(key); \
+ hashv = 0; \
+ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
+ hashv += _ho_key[_ho_i]; \
+ hashv += (hashv << 10); \
+ hashv ^= (hashv >> 6); \
+ } \
+ hashv += (hashv << 3); \
+ hashv ^= (hashv >> 11); \
+ hashv += (hashv << 15); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#define HASH_JEN_MIX(a,b,c) \
+do { \
+ a -= b; a -= c; a ^= ( c >> 13 ); \
+ b -= c; b -= a; b ^= ( a << 8 ); \
+ c -= a; c -= b; c ^= ( b >> 13 ); \
+ a -= b; a -= c; a ^= ( c >> 12 ); \
+ b -= c; b -= a; b ^= ( a << 16 ); \
+ c -= a; c -= b; c ^= ( b >> 5 ); \
+ a -= b; a -= c; a ^= ( c >> 3 ); \
+ b -= c; b -= a; b ^= ( a << 10 ); \
+ c -= a; c -= b; c ^= ( b >> 15 ); \
+} while (0)
+
+#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hj_i,_hj_j,_hj_k; \
+ unsigned const char *_hj_key=(unsigned const char*)(key); \
+ hashv = 0xfeedbeef; \
+ _hj_i = _hj_j = 0x9e3779b9; \
+ _hj_k = (unsigned)(keylen); \
+ while (_hj_k >= 12) { \
+ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ + ( (unsigned)_hj_key[2] << 16 ) \
+ + ( (unsigned)_hj_key[3] << 24 ) ); \
+ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ + ( (unsigned)_hj_key[6] << 16 ) \
+ + ( (unsigned)_hj_key[7] << 24 ) ); \
+ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ + ( (unsigned)_hj_key[10] << 16 ) \
+ + ( (unsigned)_hj_key[11] << 24 ) ); \
+ \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ \
+ _hj_key += 12; \
+ _hj_k -= 12; \
+ } \
+ hashv += keylen; \
+ switch ( _hj_k ) { \
+ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
+ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
+ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
+ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
+ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
+ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
+ case 5: _hj_j += _hj_key[4]; \
+ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
+ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
+ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
+ case 1: _hj_i += _hj_key[0]; \
+ } \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned const char *_sfh_key=(unsigned const char*)(key); \
+ uint32_t _sfh_tmp, _sfh_len = keylen; \
+ \
+ int _sfh_rem = _sfh_len & 3; \
+ _sfh_len >>= 2; \
+ hashv = 0xcafebabe; \
+ \
+ /* Main loop */ \
+ for (;_sfh_len > 0; _sfh_len--) { \
+ hashv += get16bits (_sfh_key); \
+ _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \
+ hashv = (hashv << 16) ^ _sfh_tmp; \
+ _sfh_key += 2*sizeof (uint16_t); \
+ hashv += hashv >> 11; \
+ } \
+ \
+ /* Handle end cases */ \
+ switch (_sfh_rem) { \
+ case 3: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 16; \
+ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \
+ hashv += hashv >> 11; \
+ break; \
+ case 2: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 11; \
+ hashv += hashv >> 17; \
+ break; \
+ case 1: hashv += *_sfh_key; \
+ hashv ^= hashv << 10; \
+ hashv += hashv >> 1; \
+ } \
+ \
+ /* Force "avalanching" of final 127 bits */ \
+ hashv ^= hashv << 3; \
+ hashv += hashv >> 5; \
+ hashv ^= hashv << 4; \
+ hashv += hashv >> 17; \
+ hashv ^= hashv << 25; \
+ hashv += hashv >> 6; \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ * gcc -m64 -dM -E - < /dev/null (on gcc)
+ * cc -## a.c (where a.c is a simple test file) (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
+ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
+ MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do { \
+ _h ^= _h >> 16; \
+ _h *= 0x85ebca6b; \
+ _h ^= _h >> 13; \
+ _h *= 0xc2b2ae35l; \
+ _h ^= _h >> 16; \
+} while(0)
+
+#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ const uint8_t *_mur_data = (const uint8_t*)(key); \
+ const int _mur_nblocks = (keylen) / 4; \
+ uint32_t _mur_h1 = 0xf88D5353; \
+ uint32_t _mur_c1 = 0xcc9e2d51; \
+ uint32_t _mur_c2 = 0x1b873593; \
+ uint32_t _mur_k1 = 0; \
+ const uint8_t *_mur_tail; \
+ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
+ int _mur_i; \
+ for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
+ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ \
+ _mur_h1 ^= _mur_k1; \
+ _mur_h1 = MUR_ROTL32(_mur_h1,13); \
+ _mur_h1 = _mur_h1*5+0xe6546b64; \
+ } \
+ _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \
+ _mur_k1=0; \
+ switch((keylen) & 3) { \
+ case 3: _mur_k1 ^= _mur_tail[2] << 16; \
+ case 2: _mur_k1 ^= _mur_tail[1] << 8; \
+ case 1: _mur_k1 ^= _mur_tail[0]; \
+ _mur_k1 *= _mur_c1; \
+ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
+ _mur_k1 *= _mur_c2; \
+ _mur_h1 ^= _mur_k1; \
+ } \
+ _mur_h1 ^= (keylen); \
+ MUR_FMIX(_mur_h1); \
+ hashv = _mur_h1; \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+#endif /* HASH_USING_NO_STRICT_ALIASING */
+
+/* key comparison function; return 0 if keys equal */
+#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
+do { \
+ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
+ else out=NULL; \
+ while (out) { \
+ if ((out)->hh.keylen == keylen_in) { \
+ if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \
+ } \
+ if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
+ else out = NULL; \
+ } \
+} while(0)
+
+/* add an item to a bucket */
+#define HASH_ADD_TO_BKT(head,addhh) \
+do { \
+ head.count++; \
+ (addhh)->hh_next = head.hh_head; \
+ (addhh)->hh_prev = NULL; \
+ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
+ (head).hh_head=addhh; \
+ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
+ && (addhh)->tbl->noexpand != 1) { \
+ HASH_EXPAND_BUCKETS((addhh)->tbl); \
+ } \
+} while(0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del) \
+ (head).count--; \
+ if ((head).hh_head == hh_del) { \
+ (head).hh_head = hh_del->hh_next; \
+ } \
+ if (hh_del->hh_prev) { \
+ hh_del->hh_prev->hh_next = hh_del->hh_next; \
+ } \
+ if (hh_del->hh_next) { \
+ hh_del->hh_next->hh_prev = hh_del->hh_prev; \
+ }
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ * ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(tbl) \
+do { \
+ unsigned _he_bkt; \
+ unsigned _he_bkt_i; \
+ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
+ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
+ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
+ memset(_he_new_buckets, 0, \
+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ tbl->ideal_chain_maxlen = \
+ (tbl->num_items >> (tbl->log2_num_buckets+1)) + \
+ ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
+ tbl->nonideal_items = 0; \
+ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
+ { \
+ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
+ while (_he_thh) { \
+ _he_hh_nxt = _he_thh->hh_next; \
+ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
+ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
+ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
+ tbl->nonideal_items++; \
+ _he_newbkt->expand_mult = _he_newbkt->count / \
+ tbl->ideal_chain_maxlen; \
+ } \
+ _he_thh->hh_prev = NULL; \
+ _he_thh->hh_next = _he_newbkt->hh_head; \
+ if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
+ _he_thh; \
+ _he_newbkt->hh_head = _he_thh; \
+ _he_thh = _he_hh_nxt; \
+ } \
+ } \
+ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+ tbl->num_buckets *= 2; \
+ tbl->log2_num_buckets++; \
+ tbl->buckets = _he_new_buckets; \
+ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
+ (tbl->ineff_expands+1) : 0; \
+ if (tbl->ineff_expands > 1) { \
+ tbl->noexpand=1; \
+ uthash_noexpand_fyi(tbl); \
+ } \
+ uthash_expand_fyi(tbl); \
+} while(0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn) \
+do { \
+ unsigned _hs_i; \
+ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
+ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
+ if (head) { \
+ _hs_insize = 1; \
+ _hs_looping = 1; \
+ _hs_list = &((head)->hh); \
+ while (_hs_looping) { \
+ _hs_p = _hs_list; \
+ _hs_list = NULL; \
+ _hs_tail = NULL; \
+ _hs_nmerges = 0; \
+ while (_hs_p) { \
+ _hs_nmerges++; \
+ _hs_q = _hs_p; \
+ _hs_psize = 0; \
+ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
+ _hs_psize++; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ if (! (_hs_q) ) break; \
+ } \
+ _hs_qsize = _hs_insize; \
+ while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
+ if (_hs_psize == 0) { \
+ _hs_e = _hs_q; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_qsize--; \
+ } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
+ _hs_e = _hs_p; \
+ if (_hs_p){ \
+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \
+ ((void*)((char*)(_hs_p->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ } \
+ _hs_psize--; \
+ } else if (( \
+ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+ ) <= 0) { \
+ _hs_e = _hs_p; \
+ if (_hs_p){ \
+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \
+ ((void*)((char*)(_hs_p->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ } \
+ _hs_psize--; \
+ } else { \
+ _hs_e = _hs_q; \
+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \
+ ((void*)((char*)(_hs_q->next) + \
+ (head)->hh.tbl->hho)) : NULL); \
+ _hs_qsize--; \
+ } \
+ if ( _hs_tail ) { \
+ _hs_tail->next = ((_hs_e) ? \
+ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
+ } else { \
+ _hs_list = _hs_e; \
+ } \
+ if (_hs_e) { \
+ _hs_e->prev = ((_hs_tail) ? \
+ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
+ } \
+ _hs_tail = _hs_e; \
+ } \
+ _hs_p = _hs_q; \
+ } \
+ if (_hs_tail){ \
+ _hs_tail->next = NULL; \
+ } \
+ if ( _hs_nmerges <= 1 ) { \
+ _hs_looping=0; \
+ (head)->hh.tbl->tail = _hs_tail; \
+ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
+ } \
+ _hs_insize *= 2; \
+ } \
+ HASH_FSCK(hh,head); \
+ } \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
+do { \
+ unsigned _src_bkt, _dst_bkt; \
+ void *_last_elt=NULL, *_elt; \
+ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
+ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
+ if (src) { \
+ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
+ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
+ _src_hh; \
+ _src_hh = _src_hh->hh_next) { \
+ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
+ if (cond(_elt)) { \
+ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
+ _dst_hh->key = _src_hh->key; \
+ _dst_hh->keylen = _src_hh->keylen; \
+ _dst_hh->hashv = _src_hh->hashv; \
+ _dst_hh->prev = _last_elt; \
+ _dst_hh->next = NULL; \
+ if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
+ if (!dst) { \
+ DECLTYPE_ASSIGN(dst,_elt); \
+ HASH_MAKE_TABLE(hh_dst,dst); \
+ } else { \
+ _dst_hh->tbl = (dst)->hh_dst.tbl; \
+ } \
+ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
+ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
+ (dst)->hh_dst.tbl->num_items++; \
+ _last_elt = _elt; \
+ _last_elt_hh = _dst_hh; \
+ } \
+ } \
+ } \
+ } \
+ HASH_FSCK(hh_dst,dst); \
+} while (0)
+
+#define HASH_CLEAR(hh,head) \
+do { \
+ if (head) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head)=NULL; \
+ } \
+} while(0)
+
+#define HASH_OVERHEAD(hh,head) \
+ ((head) ? ( \
+ (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
+ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
+ (sizeof(UT_hash_table)) + \
+ (HASH_BLOOM_BYTELEN)))) : 0)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp) \
+for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \
+ el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
+#else
+#define HASH_ITER(hh,head,el,tmp) \
+for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \
+ el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
+
+typedef struct UT_hash_bucket {
+ struct UT_hash_handle *hh_head;
+ unsigned count;
+
+ /* expand_mult is normally set to 0. In this situation, the max chain length
+ * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+ * the bucket's chain exceeds this length, bucket expansion is triggered).
+ * However, setting expand_mult to a non-zero value delays bucket expansion
+ * (that would be triggered by additions to this particular bucket)
+ * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+ * (The multiplier is simply expand_mult+1). The whole idea of this
+ * multiplier is to reduce bucket expansions, since they are expensive, in
+ * situations where we know that a particular bucket tends to be overused.
+ * It is better to let its chain length grow to a longer yet-still-bounded
+ * value, than to do an O(n) bucket expansion too often.
+ */
+ unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1
+#define HASH_BLOOM_SIGNATURE 0xb12220f2
+
+typedef struct UT_hash_table {
+ UT_hash_bucket *buckets;
+ unsigned num_buckets, log2_num_buckets;
+ unsigned num_items;
+ struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
+ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+ /* in an ideal situation (all buckets used equally), no bucket would have
+ * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+ unsigned ideal_chain_maxlen;
+
+ /* nonideal_items is the number of items in the hash whose chain position
+ * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+ * hash distribution; reaching them in a chain traversal takes >ideal steps */
+ unsigned nonideal_items;
+
+ /* ineffective expands occur when a bucket doubling was performed, but
+ * afterward, more than half the items in the hash had nonideal chain
+ * positions. If this happens on two consecutive expansions we inhibit any
+ * further expansion, as it's not helping; this happens when the hash
+ * function isn't a good fit for the key domain. When expansion is inhibited
+ * the hash will still work, albeit no longer in constant time. */
+ unsigned ineff_expands, noexpand;
+
+ uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+ uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+ uint8_t *bloom_bv;
+ char bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+ struct UT_hash_table *tbl;
+ void *prev; /* prev element in app order */
+ void *next; /* next element in app order */
+ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
+ struct UT_hash_handle *hh_next; /* next hh in bucket order */
+ void *key; /* ptr to enclosing struct's key */
+ unsigned keylen; /* enclosing struct's key len */
+ unsigned hashv; /* result of hash-fcn(key) */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/app/wlib/gtklib/wpref.c b/app/wlib/gtklib/wpref.c
new file mode 100644
index 0000000..b79c8d2
--- /dev/null
+++ b/app/wlib/gtklib/wpref.c
@@ -0,0 +1,502 @@
+/** \file wpref.c Handle loading and saving preferences.
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/gtklib/wpref.c,v 1.15 2010-04-28 04:04:38 dspagnol Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#include "wlib.h"
+#include "dynarr.h"
+#include "i18n.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+#ifdef XTRKCAD_CMAKE_BUILD
+#include "xtrkcad-config.h"
+#endif
+
+extern char wAppName[];
+extern char wConfigName[];
+static char appLibDir[BUFSIZ];
+static char appWorkDir[BUFSIZ];
+static char userHomeDir[BUFSIZ];
+
+EXPORT void wInitAppName(char *appName)
+{
+ strcpy(wAppName, appName);
+}
+
+/*
+ *******************************************************************************
+ *
+ * Get Dir Names
+ *
+ *******************************************************************************
+ */
+
+
+EXPORT const char * wGetAppLibDir( void )
+/** Find the directory where configuration files, help, demos etc are installed.
+ * The search order is:
+ * 1. Directory specified by the XTRKCADLIB environment variable
+ * 2. Directory specified by XTRKCAD_INSTALL_PREFIX/share/xtrkcad
+ * 3. /usr/lib/xtrkcad
+ * 4. /usr/local/lib/xtrkcad
+ *
+ * \return pointer to directory name
+ */
+{
+ char * cp, *ep;
+ char msg[BUFSIZ*2];
+ char envvar[80];
+ struct stat buf;
+
+ if (appLibDir[0] != '\0') {
+ return appLibDir;
+ }
+
+ for (cp=wAppName,ep=envvar; *cp; cp++,ep++)
+ *ep = toupper(*cp);
+ strcpy( ep, "LIB" );
+ ep = getenv( envvar );
+ if (ep != NULL) {
+ if ((stat( ep, &buf) == 0 ) && S_ISDIR( buf.st_mode)) {
+ strncpy( appLibDir, ep, sizeof appLibDir );
+ return appLibDir;
+ }
+ }
+
+#ifdef XTRKCAD_CMAKE_BUILD
+ strcpy(appLibDir, XTRKCAD_INSTALL_PREFIX);
+ strcat(appLibDir, "/share/");
+ strcat(appLibDir, wAppName);
+
+ if ((stat( appLibDir, &buf) == 0 ) && S_ISDIR( buf.st_mode)) {
+ return appLibDir;
+ }
+#endif
+
+ strcpy( appLibDir, "/usr/lib/" );
+ strcat( appLibDir, wAppName );
+ if ((stat( appLibDir, &buf) == 0 ) && S_ISDIR( buf.st_mode)) {
+ return appLibDir;
+ }
+
+ strcpy( appLibDir, "/usr/local/lib/" );
+ strcat( appLibDir, wAppName );
+ if ((stat( appLibDir, &buf) == 0 ) && S_ISDIR( buf.st_mode)) {
+ return appLibDir;
+ }
+
+ sprintf( msg,
+ _("The required configuration files could not be located in the expected location.\n\n"
+ "Usually this is an installation problem. Make sure that these files are installed in either \n"
+ " %s/share/xtrkcad or\n"
+ " /usr/lib/%s or\n"
+ " /usr/local/lib/%s\n"
+ "If this is not possible, the environment variable %s must contain "
+ "the name of the correct directory."),
+ XTRKCAD_INSTALL_PREFIX, wAppName, wAppName, envvar );
+ wNoticeEx( NT_ERROR, msg, _("Ok"), NULL );
+ appLibDir[0] = '\0';
+ wExit(0);
+ return NULL;
+}
+
+/**
+ * Get the working directory for the application. This directory is used for storing
+ * internal files including rc files. If it doesn't exist, the directory is created
+ * silently.
+ *
+ * \return pointer to the working directory
+ */
+
+
+EXPORT const char * wGetAppWorkDir(
+ void )
+{
+ char tmp[BUFSIZ+20];
+ char * homeDir;
+ DIR *dirp;
+
+ if (appWorkDir[0] != '\0')
+ return appWorkDir;
+
+ if ((homeDir = getenv( "HOME" )) == NULL) {
+ wNoticeEx( NT_ERROR, _("HOME is not set"), _("Exit"), NULL);
+ wExit(0);
+ }
+ sprintf( appWorkDir, "%s/.%s", homeDir, wAppName );
+ if ( (dirp = opendir(appWorkDir)) != NULL ) {
+ closedir(dirp);
+ } else {
+ if ( mkdir( appWorkDir, 0777 ) == -1 ) {
+ sprintf( tmp, _("Cannot create %s"), appWorkDir );
+ wNoticeEx( NT_ERROR, tmp, _("Exit"), NULL );
+ wExit(0);
+ } else {
+ /*
+ * check for default configuration file and copy to
+ * the workdir if it exists
+ */
+ struct stat stFileInfo;
+ char appEtcConfig[BUFSIZ];
+ sprintf( appEtcConfig, "/etc/%s.rc", wAppName );
+
+ if ( stat( appEtcConfig, &stFileInfo ) == 0 ) {
+ char copyConfigCmd[(BUFSIZ * 2) + 3];
+ sprintf( copyConfigCmd, "cp %s %s", appEtcConfig, appWorkDir );
+ system( copyConfigCmd );
+ }
+ }
+ }
+ return appWorkDir;
+}
+
+/**
+ * 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
+ */
+
+EXPORT const char *wGetUserHomeDir( void )
+{
+ char *homeDir;
+
+ if( userHomeDir[ 0 ] != '\0' )
+ return userHomeDir;
+
+ if ((homeDir = getenv( "HOME" )) == NULL) {
+ wNoticeEx( NT_ERROR, _("HOME is not set"), _("Exit"), NULL);
+ wExit(0);
+ } else {
+ strcpy( userHomeDir, homeDir );
+ }
+
+ return userHomeDir;
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * Preferences
+ *
+ *******************************************************************************
+ */
+
+typedef struct {
+ char * section;
+ char * name;
+ wBool_t present;
+ wBool_t dirty;
+ char * val;
+ } prefs_t;
+dynArr_t prefs_da;
+#define prefs(N) DYNARR_N(prefs_t,prefs_da,N)
+wBool_t prefInitted = FALSE;
+
+static void readPrefs( void )
+{
+ char tmp[BUFSIZ], *sp, *np, *vp, *cp;
+ const char * workDir;
+ FILE * prefFile;
+ prefs_t * p;
+
+ prefInitted = TRUE;
+ workDir = wGetAppWorkDir();
+ sprintf( tmp, "%s/%s.rc", workDir, wConfigName );
+ prefFile = fopen( tmp, "r" );
+ if (prefFile == NULL)
+ return;
+ while ( ( fgets(tmp, sizeof tmp, prefFile) ) != NULL ) {
+ sp = tmp;
+ while ( *sp==' ' || *sp=='\t' ) sp++;
+ if ( *sp == '\n' || *sp == '#' )
+ continue;
+ np = strchr( sp, '.' );
+ if (np == NULL) {
+ wNoticeEx( NT_INFORMATION, tmp, _("Continue"), NULL );
+ continue;
+ }
+ *np++ = '\0';
+ while ( *np==' ' || *np=='\t' ) np++;
+ vp = strchr( np, ':' );
+ if (vp == NULL) {
+ wNoticeEx( NT_INFORMATION, tmp, _("Continue"), NULL );
+ continue;
+ }
+ *vp++ = '\0';
+ while ( *vp==' ' || *vp=='\t' ) vp++;
+ cp = vp + strlen(vp) -1;
+ while ( cp >= vp && (*cp=='\n' || *cp==' ' || *cp=='\t') ) cp--;
+ cp[1] = '\0';
+ DYNARR_APPEND( prefs_t, prefs_da, 10 );
+ p = &prefs(prefs_da.cnt-1);
+ p->name = strdup(np);
+ p->section = strdup(sp);
+ p->dirty = FALSE;
+ p->val = strdup(vp);
+ }
+ fclose( prefFile );
+}
+
+/**
+ * Store a string in the user preferences.
+ *
+ * \param section IN section in preferences file
+ * \param name IN name of parameter
+ * \param sval IN value to save
+ */
+
+EXPORT void wPrefSetString(
+ const char * section, /* Section */
+ const char * name, /* Name */
+ const char * sval ) /* Value */
+{
+ prefs_t * p;
+
+ if (!prefInitted)
+ readPrefs();
+
+ 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 = strdup( sval );
+ return;
+ }
+ }
+ DYNARR_APPEND( prefs_t, prefs_da, 10 );
+ p = &prefs(prefs_da.cnt-1);
+ p->name = strdup(name);
+ p->section = strdup(section);
+ p->dirty = TRUE;
+ p->val = strdup(sval);
+}
+
+
+EXPORT const char * wPrefGetString(
+ const char * section, /* Section */
+ const char * name ) /* Name */
+/*
+*/
+{
+ prefs_t * p;
+
+ if (!prefInitted)
+ readPrefs();
+
+ for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) {
+ if ( strcmp( p->section, section ) == 0 && strcmp( p->name, name ) == 0 ) {
+ return p->val;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Store an integer value in the user preferences.
+ *
+ * \param section IN section in preferences file
+ * \param name IN name of parameter
+ * \param lval IN value to save
+ */
+
+EXPORT void wPrefSetInteger(
+ const char * section, /* Section */
+ const char * name, /* Name */
+ long lval ) /* Value */
+{
+ char tmp[20];
+
+ sprintf(tmp, "%ld", lval );
+ wPrefSetString( section, name, tmp );
+}
+
+/**
+ * Read an integer value from the user preferences.
+ *
+ * \param section IN section in preferences file
+ * \param name IN name of parameter
+ * \param res OUT resulting value
+ * \param default IN default value
+ * \return TRUE if value differs from default, FALSE if the same
+ */
+
+EXPORT wBool_t wPrefGetInteger(
+ const char * section, /* Section */
+ const char * name, /* Name */
+ long * res, /* Address of result */
+ long def ) /* Default value */
+{
+ 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;
+}
+
+/**
+ * Save a float value in the preferences file.
+ *
+ * \param section IN the file section into which the value should be saved
+ * \param name IN the name of the preference
+ * \param lval IN the value
+ */
+
+EXPORT 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 );
+}
+
+/**
+ * Read a float from the preferencesd file.
+ *
+ * \param section IN the file section from which the value should be read
+ * \param name IN the name of the preference
+ * \param res OUT pointer for the value
+ * \param def IN default value
+ * \return TRUE if value was read, FALSE if default value is used
+ */
+
+
+EXPORT 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;
+}
+
+
+EXPORT const char * wPrefGetSectionItem(
+ const char * sectionName,
+ wIndex_t * index,
+ const char ** name )
+{
+ prefs_t * p;
+
+ if (!prefInitted)
+ readPrefs();
+
+ if ( *index >= prefs_da.cnt )
+ return NULL;
+
+ for (p=&prefs((*index)++); p<&prefs(prefs_da.cnt); p++,(*index)++) {
+ if ( strcmp( p->section, sectionName ) == 0 ) {
+ if ( name )
+ *name = p->name;
+ return p->val;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Save the configuration to a file. The config parameters are held and updated in an array.
+ * To make the settings persistant, this function has to be called.
+ *
+ */
+
+EXPORT void wPrefFlush(
+ void )
+/*
+*/
+{
+ prefs_t * p;
+ char tmp[BUFSIZ];
+ const char *workDir;
+ FILE * prefFile;
+
+ if (!prefInitted)
+ return;
+
+ workDir = wGetAppWorkDir();
+ sprintf( tmp, "%s/%s.rc", workDir, wConfigName );
+ prefFile = fopen( tmp, "w" );
+ if (prefFile == NULL)
+ return;
+
+ for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) {
+ fprintf( prefFile, "%s.%s: %s\n", p->section, p->name, p->val );
+ }
+ fclose( prefFile );
+}
+
+
+EXPORT void wPrefReset(
+ void )
+/*
+*/
+{
+ prefs_t * p;
+
+ prefInitted = FALSE;
+ 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/include/ctl3d.h b/app/wlib/include/ctl3d.h
new file mode 100644
index 0000000..989c28d
--- /dev/null
+++ b/app/wlib/include/ctl3d.h
@@ -0,0 +1,5 @@
+/*****************************************************/
+/* */
+/* dummy file for compatibility with VS 6.0 */
+/* */
+/*****************************************************/
diff --git a/app/wlib/include/getopt.h b/app/wlib/include/getopt.h
new file mode 100644
index 0000000..e9a8354
--- /dev/null
+++ b/app/wlib/include/getopt.h
@@ -0,0 +1,25 @@
+/*
+ getopt.h 1.2 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
+*/
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+int getopt(int argc, char *argv[], const char *optstring);
diff --git a/app/wlib/include/mswlib.h b/app/wlib/include/mswlib.h
new file mode 100644
index 0000000..4a3f799
--- /dev/null
+++ b/app/wlib/include/mswlib.h
@@ -0,0 +1,9 @@
+
+#define WAPPICON (980)
+#define WM_F1DOWN (WM_USER+10)
+#define WM_NOTVALID (WM_USER+11)
+#define IDM_DOHELP 999
+#define IDM_PRINTAPP 998
+#define IDM_PRINTPAGE 997
+#define IDM_ABOUT 100
+
diff --git a/app/wlib/include/mswlib.rc b/app/wlib/include/mswlib.rc
new file mode 100644
index 0000000..bf13e6b
--- /dev/null
+++ b/app/wlib/include/mswlib.rc
@@ -0,0 +1,13 @@
+msw-accel ACCELERATORS
+BEGIN
+ VK_F1, IDM_DOHELP, VIRTKEY
+END
+
+MswAbortDlg DIALOG 20, 20, 90, 64
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "Printing"
+BEGIN
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 29, 44, 32, 14, WS_GROUP
+ CTEXT "Now printing", -1, 0, 8, 90, 8
+ CTEXT "Page", IDM_PRINTPAGE, 0, 18, 90, 8
+END
diff --git a/app/wlib/include/wcolors.h b/app/wlib/include/wcolors.h
new file mode 100644
index 0000000..46d15a8
--- /dev/null
+++ b/app/wlib/include/wcolors.h
@@ -0,0 +1,42 @@
+/* Some colors */
+#define wDrawColorWhite (0)
+#define wDrawColorBlack (1)
+#define wDrawColorRed (2)
+#define wDrawColorGreen (3)
+#define wDrawColorBlue (4)
+#define wDrawColorYellow (5)
+#define wDrawColorPurple (6)
+#define wDrawColorAqua (7)
+#define wDrawColorDkRed (8)
+#define wDrawColorDkGreen (9)
+#define wDrawColorDkBlue (10)
+#define wDrawColorDkYellow (11)
+#define wDrawColorDkPurple (12)
+#define wDrawColorDkAqua (13)
+#define wDrawColorRoyalBlue (14)
+#define wDrawColorDeepSkyBlue (15)
+#define wDrawColorLightSkyBlue (16)
+#define wDrawColorSteelBlue (17)
+#define wDrawColorPowderBlue (18)
+#define wDrawColorAquamarine (19)
+#define wDrawColorSeaGreen (20)
+#define wDrawColorPaleGreen (21)
+#define wDrawColorLawnGreen (22)
+#define wDrawColorLimeGreen (23)
+#define wDrawColorForestGreen (24)
+#define wDrawColorGold (25)
+#define wDrawColorRosyBrown (26)
+#define wDrawColorSaddleBrown (27)
+#define wDrawColorBeige (28)
+#define wDrawColorTan (29)
+#define wDrawColorChocolate (30)
+#define wDrawColorBrown (31)
+#define wDrawColorOrange (32)
+#define wDrawColorCoral (33)
+#define wDrawColorTomato (34)
+#define wDrawColorHotPink (35)
+#define wDrawColorPink (36)
+#define wDrawColorMaroon (37)
+#define wDrawColorViolet (38)
+#define wDrawColorPurple2 (39)
+
diff --git a/app/wlib/include/wlib.h b/app/wlib/include/wlib.h
new file mode 100644
index 0000000..4582231
--- /dev/null
+++ b/app/wlib/include/wlib.h
@@ -0,0 +1,690 @@
+/** \file wlib.h
+ * Commaon definitions and declarations for the wlib library
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/include/wlib.h,v 1.18 2010-04-28 04:04:39 dspagnol Exp $
+ */
+
+#ifndef WIN_H
+#define WIN_H
+#ifdef WINDOWS
+#include <stdio.h>
+#endif
+
+#ifdef USE_SIMPLE_GETTEXT
+char *bindtextdomain( char *domainname, char *dirname );
+char *bind_textdomain_codeset(char *domainname, char *codeset );
+char *textdomain( char *domainname );
+char *gettext( char *msgid );
+
+char *g_win32_getlocale (void);
+#endif
+
+/*
+ * Interface types
+ */
+
+typedef long wInteger_t;
+typedef int wPos_t;
+typedef int wBool_t;
+typedef int wIndex_t;
+
+/*
+ * Opaque Pointers
+ */
+typedef struct wWin_t * wWin_p;
+typedef struct wControl_t * wControl_p;
+typedef struct wButton_t * wButton_p;
+typedef struct wString_t * wString_p;
+typedef struct wInteger_t * wInteger_p;
+typedef struct wFloat_t * wFloat_p;
+typedef struct wList_t * wList_p;
+typedef struct wChoice_t * wChoice_p;
+typedef struct wDraw_t * wDraw_p;
+typedef struct wMenu_t * wMenu_p;
+typedef struct wText_t * wText_p;
+typedef struct wMessage_t * wMessage_p;
+typedef struct wLine_t * wLine_p;
+typedef struct wMenuList_t * wMenuList_p;
+typedef struct wMenuPush_t * wMenuPush_p;
+typedef struct wMenuRadio_t * wMenuRadio_p;
+typedef struct wMenuToggle_t* wMenuToggle_p;
+typedef struct wBox_t * wBox_p;
+typedef struct wIcon_t * wIcon_p;
+typedef struct wDrawBitMap_t * wDrawBitMap_p;
+typedef struct wFont_t * wFont_p;
+typedef struct wBitmap_t * wBitmap_p;
+typedef int wDrawWidth;
+typedef int wDrawColor;
+
+typedef struct {
+ const char * name;
+ const char * value;
+ } wBalloonHelp_t;
+
+extern long debugWindow;
+extern long wDebugFont;
+
+
+/*------------------------------------------------------------------------------
+ *
+ * System Interface
+ */
+
+void wInitAppName(char *appName);
+
+const char * wGetAppLibDir( void );
+const char * wGetAppWorkDir( void );
+const char * wGetUserHomeDir( void );
+wBool_t wCheckExecutable( void );
+
+void wBeep( void );
+wBool_t wNotice( const char *, const char *, const char * );
+int wNotice3( const char *, const char *, const char *, const char * );
+void wHelp( const char * );
+
+#define NT_INFORMATION 1
+#define NT_WARNING 2
+#define NT_ERROR 4
+
+wBool_t wNoticeEx( int type, const char * msg, const char * yes, const char * no );
+
+
+
+void wSetBalloonHelp ( wBalloonHelp_t * );
+void wEnableBalloonHelp ( int );
+void wBalloonHelpUpdate ( void );
+
+void wFlush( void );
+
+typedef void (*wAlarmCallBack_p)( void );
+void wAlarm( long, wAlarmCallBack_p );
+void wPause( long );
+unsigned long wGetTimer( void );
+
+void wExit( int );
+
+typedef enum { wCursorNormal,
+ wCursorWait,
+ wCursorIBeam,
+ wCursorCross,
+ wCursorQuestion } wCursor_t;
+void wSetCursor( wCursor_t );
+
+const char * wMemStats( void );
+
+#define WKEY_SHIFT (1<<1)
+#define WKEY_CTRL (1<<2)
+#define WKEY_ALT (1<<3)
+int wGetKeyState( void );
+
+void wGetDisplaySize( wPos_t*, wPos_t* );
+
+wIcon_p wIconCreateBitMap( wPos_t, wPos_t, const char * bits, wDrawColor );
+wIcon_p wIconCreatePixMap( char *[] );
+void wIconSetColor( wIcon_p, wDrawColor );
+void wIconDraw( wDraw_p d, wIcon_p bm, wPos_t x, wPos_t y );
+
+void wConvertToCharSet( char *, int );
+void wConvertFromCharSet( char *, int );
+#ifdef WINDOWS
+FILE * wFileOpen( const char *, const char * );
+#endif
+
+/*------------------------------------------------------------------------------
+ *
+ * Main and Popup Windows
+ */
+
+/* Creation CallBacks */
+typedef enum {
+ wClose_e,
+ wResize_e,
+ wQuit_e,
+ wRedraw_e }
+ winProcEvent;
+typedef void (*wWinCallBack_p)( wWin_p, winProcEvent, void * );
+
+/* Creation Options */
+#define F_AUTOSIZE (1L<<1)
+#define F_HEADER (1L<<2)
+#define F_RESIZE (1L<<3)
+#define F_BLOCK (1L<<4)
+#define F_MENUBAR (1L<<5)
+#define F_NOTAB (1L<<8)
+#define F_RECALLPOS (1L<<9)
+#define F_RECALLSIZE (1L<<10)
+#define F_TOP (1L<<11)
+#define F_CENTER (1L<<12)
+#define F_HIDE (1L<<12)
+
+wWin_p wWinMainCreate( const char *, wPos_t, wPos_t, const char *, const char *, const char *,
+ long, wWinCallBack_p, void * );
+wWin_p wWinPopupCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, const char *,
+ long, wWinCallBack_p, void * );
+
+wWin_p wMain( int, char *[] );
+void wWinSetBigIcon( wWin_p, wIcon_p );
+void wWinSetSmallIcon( wWin_p, wIcon_p );
+void wWinShow( wWin_p, wBool_t );
+wBool_t wWinIsVisible( wWin_p );
+void wWinGetSize ( wWin_p, wPos_t *, wPos_t * );
+void wWinSetSize( wWin_p, wPos_t, wPos_t );
+void wWinSetTitle( wWin_p, const char * );
+void wWinSetBusy( wWin_p, wBool_t );
+const char * wWinGetTitle( wWin_p );
+void wWinClear( wWin_p, wPos_t, wPos_t, wPos_t, wPos_t );
+void wMessage( wWin_p, const char *, wBool_t );
+void wWinTop( wWin_p );
+void wWinDoCancel( wWin_p );
+void wWinBlockEnable( wBool_t );
+
+int wCreateSplash( char *appName, char *appVer );
+int wSetSplashInfo( char *msg );
+void wDestroySplash( void );
+
+/*------------------------------------------------------------------------------
+ *
+ * Controls in general
+ */
+
+/* Creation Options */
+#define BO_ICON (1L<<0)
+#define BO_DISABLED (1L<<1)
+#define BO_READONLY (1L<<2)
+#define BO_NOTAB (1L<<8)
+#define BO_BORDER (1L<<9)
+
+wPos_t wLabelWidth( const char * );
+const char * wControlGetHelp( wControl_p );
+void wControlSetHelp( wControl_p, const char * );
+void wControlShow( wControl_p, wBool_t );
+wPos_t wControlGetWidth( wControl_p );
+wPos_t wControlGetHeight( wControl_p );
+wPos_t wControlGetPosX( wControl_p );
+wPos_t wControlGetPosY( wControl_p );
+void wControlSetPos( wControl_p, wPos_t, wPos_t );
+void wControlSetFocus( wControl_p );
+void wControlActive( wControl_p, wBool_t );
+void wControlSetBalloon( wControl_p, wPos_t, wPos_t, const char * );
+void wControlSetLabel( wControl_p, const char * );
+void wControlSetBalloonText( wControl_p, const char * );
+void wControlSetContext( wControl_p, void * );
+void wControlHilite( wControl_p, wBool_t );
+
+void wControlLinkedSet( wControl_p b1, wControl_p b2 );
+void wControlLinkedActive( wControl_p b, int active );
+
+/*------------------------------------------------------------------------------
+ *
+ * Push buttons
+ */
+
+/* Creation CallBacks */
+typedef void (*wButtonCallBack_p)( void * );
+
+/* Creation Options */
+#define BB_DEFAULT (1L<<5)
+#define BB_CANCEL (1L<<6)
+#define BB_HELP (1L<<7)
+
+wButton_p wButtonCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ wPos_t, wButtonCallBack_p, void * );
+void wButtonSetLabel( wButton_p, const char * );
+void wButtonSetColor( wButton_p, wDrawColor );
+void wButtonSetBusy( wButton_p, wBool_t );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Radio and Toggle (Choice) Buttons
+ */
+
+/* Creation CallBacks */
+typedef void (*wChoiceCallBack_p)( long, void * );
+
+/* Creation Options */
+#define BC_ICON (1L<<0)
+#define BC_HORZ (1L<<22)
+#define BC_NONE (1L<<19)
+#define BC_NOBORDER (1L<<15)
+
+wChoice_p wRadioCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ const char **, long *, wChoiceCallBack_p, void * );
+wChoice_p wToggleCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ const char **, long *, wChoiceCallBack_p, void * );
+void wRadioSetValue( wChoice_p, long );
+void wToggleSetValue( wChoice_p, long );
+long wRadioGetValue( wChoice_p );
+long wToggleGetValue( wChoice_p );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * String entry
+ */
+
+#define BS_TRIM (1<<12)
+/* Creation CallBacks */
+typedef void (*wStringCallBack_p)( const char *, void * );
+wString_p wStringCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ wPos_t, char *, wIndex_t, wStringCallBack_p,
+ void * );
+void wStringSetValue( wString_p, const char * );
+void wStringSetWidth( wString_p, wPos_t );
+const char * wStringGetValue( wString_p );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Numeric Entry
+ */
+
+/* Creation CallBacks */
+typedef void (*wIntegerCallBack_p)( long, void * );
+typedef void (*wFloatCallBack_p)( double, void * );
+wInteger_p wIntegerCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ wPos_t, wInteger_t, wInteger_t, wInteger_t *,
+ wIntegerCallBack_p, void * );
+wFloat_p wFloatCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ wPos_t, double, double, double *,
+ wFloatCallBack_p, void * );
+void wIntegerSetValue( wInteger_p, wInteger_t );
+void wFloatSetValue( wFloat_p, double );
+wInteger_t wIntegerGetValue( wInteger_p );
+double wFloatGetValue( wFloat_p );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Lists
+ */
+
+/* Creation CallBacks */
+typedef void (*wListCallBack_p)( wIndex_t, const char *, wIndex_t, void *, void * );
+
+/* Creation Options */
+#define BL_DUP (1L<<16)
+#define BL_SORT (1L<<17)
+#define BL_MANY (1L<<18)
+#define BL_NONE (1L<<19)
+#define BL_SETSTAY (1L<<20)
+#define BL_DBLCLICK (1L<<21)
+#define BL_FIXFONT (1L<<22)
+#define BL_EDITABLE (1L<<23)
+#define BL_ICON (1L<<0)
+
+wList_p wListCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ long, wPos_t, int, wPos_t *, wBool_t *, const char **, long *, wListCallBack_p, void * );
+wList_p wComboListCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ long, wPos_t, long *, wListCallBack_p, void * );
+wList_p wDropListCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ long, wPos_t, long *, wListCallBack_p, void * );
+void wListClear( wList_p );
+void wListSetIndex( wList_p, wIndex_t );
+wIndex_t wListGetIndex( wList_p );
+wIndex_t wListFindValue( wList_p, const char * );
+void wListSetValue( wList_p, const char * );
+int wListGetColumnWidths( wList_p, int, wPos_t * );
+wBool_t wListSetValues( wList_p, wIndex_t, const char *, wIcon_p, void * );
+void wListSetActive( wList_p, wIndex_t, wBool_t );
+void wListSetEditable( wList_p, wBool_t );
+wIndex_t wListAddValue( wList_p, const char *, wIcon_p, void * );
+void wListDelete( wList_p, wIndex_t );
+wIndex_t wListGetValues( wList_p, char *, int, void * *, void * * );
+wIndex_t wListGetCount( wList_p );
+void * wListGetItemContext( wList_p, wIndex_t );
+wBool_t wListGetItemSelected( wList_p, wIndex_t );
+wIndex_t wListGetSelectedCount( wList_p );
+void wListSetSize( wList_p, wPos_t, wPos_t );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Messages
+ */
+
+#define BM_LARGE (1L<<24)
+#define BM_SMALL (1L<<25)
+
+#define wMessageSetFont( x ) ( x & (BM_LARGE | BM_SMALL ))
+
+#define wMessageCreate( w, p1, p2, l, p3, m ) wMessageCreateEx( w, p1, p2, l, p3, m, 0 )
+wMessage_p wMessageCreateEx( wWin_p, wPos_t, wPos_t, const char *,
+ wPos_t, const char *, long );
+
+void wMessageSetValue( wMessage_p, const char * );
+void wMessageSetWidth( wMessage_p, wPos_t );
+wPos_t wMessageGetHeight( long );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Boxes
+ */
+
+typedef enum {
+ wBoxThinB,
+ wBoxThinW,
+ wBoxAbove,
+ wBoxBelow,
+ wBoxThickB,
+ wBoxThickW,
+ wBoxRidge,
+ wBoxTrough }
+ wBoxType_e;
+wBox_p wBoxCreate( wWin_p, wPos_t, wPos_t, const char *, wBoxType_e,
+ wPos_t, wPos_t );
+void wBoxSetSize( wBox_p, wPos_t, wPos_t );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Lines
+ */
+
+typedef struct {
+ int width;
+ int x0, y0;
+ int x1, y1;
+ } wLines_t, * wLines_p;
+
+wLine_p wLineCreate( wWin_p, const char *, int, wLines_t *);
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Text
+ */
+
+/* Creation Options */
+#define BT_HSCROLL (1L<<24)
+#define BT_CHARUNITS (1L<<23)
+#define BT_FIXEDFONT (1L<<22)
+#define BT_DOBOLD (1L<<21)
+
+wText_p wTextCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long,
+ wPos_t, wPos_t );
+void wTextClear( wText_p );
+void wTextAppend( wText_p, const char * );
+void wTextSetReadonly( wText_p, wBool_t );
+int wTextGetSize( wText_p );
+void wTextGetText( wText_p, char *, int );
+wBool_t wTextGetModified( wText_p );
+void wTextReadFile( wText_p, const char * );
+wBool_t wTextSave( wText_p, const char * );
+wBool_t wTextPrint( wText_p );
+void wTextSetSize( wText_p, wPos_t, wPos_t );
+void wTextComputeSize( wText_p, int, int, wPos_t *, wPos_t * );
+void wTextSetPosition( wText_p bt, int pos );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Draw
+ */
+
+
+typedef int wDrawOpts;
+#define wDrawOptTemp (1<<0)
+#define wDrawOptNoClip (1<<1)
+
+typedef enum {
+ wDrawLineSolid,
+ wDrawLineDash }
+ wDrawLineType_e;
+
+typedef int wAction_t;
+#define wActionMove (1)
+#define wActionLDown (2)
+#define wActionLDrag (3)
+#define wActionLUp (4)
+#define wActionRDown (5)
+#define wActionRDrag (6)
+#define wActionRUp (7)
+#define wActionText (8)
+#define wActionExtKey (9)
+#define wActionWheelUp (10)
+#define wActionWheelDown (11)
+#define wActionLast wActionWheelDown
+
+
+#define wRGB(R,G,B)\
+ (long)(((((long)(R)<<16))&0xFF0000L)|((((long)(G))<<8)&0x00FF00L)|(((long)(B))&0x0000FFL))
+
+
+/* Creation CallBacks */
+typedef void (*wDrawRedrawCallBack_p)( wDraw_p, void *, wPos_t, wPos_t );
+typedef void (*wDrawActionCallBack_p)( wDraw_p, void*, wAction_t, wPos_t, wPos_t );
+
+/* Creation Options */
+#define BD_TICKS (1L<<25)
+#define BD_DIRECT (1L<<26)
+#define BD_NOCAPTURE (1L<<27)
+
+/* Create: */
+wDraw_p wDrawCreate( wWin_p, wPos_t, wPos_t, const char *, long,
+ wPos_t, wPos_t, void *,
+ wDrawRedrawCallBack_p, wDrawActionCallBack_p );
+
+/* Draw: */
+void wDrawLine( wDraw_p, wPos_t, wPos_t, wPos_t, wPos_t,
+ wDrawWidth, wDrawLineType_e, wDrawColor,
+ wDrawOpts );
+#define double2wAngle_t( A ) (A)
+typedef double wAngle_t;
+void wDrawArc( wDraw_p, wPos_t, wPos_t, wPos_t, wAngle_t, wAngle_t,
+ int, wDrawWidth, wDrawLineType_e, wDrawColor,
+ wDrawOpts );
+void wDrawPoint( wDraw_p, wPos_t, wPos_t, wDrawColor, wDrawOpts );
+#define double2wFontSize_t( FS ) (FS)
+typedef double wFontSize_t;
+void wDrawString( wDraw_p, wPos_t, wPos_t, wAngle_t, const char *, wFont_p,
+ wFontSize_t, wDrawColor, wDrawOpts );
+void wDrawFilledRectangle( wDraw_p, wPos_t, wPos_t, wPos_t, wPos_t,
+ wDrawColor, wDrawOpts );
+void wDrawFilledPolygon( wDraw_p, wPos_t [][2], wIndex_t, wDrawColor,
+ wDrawOpts );
+void wDrawFilledCircle( wDraw_p, wPos_t, wPos_t, wPos_t, wDrawColor, wDrawOpts );
+
+void wDrawGetTextSize( wPos_t *, wPos_t *, wPos_t *, wDraw_p, const char *, wFont_p,
+ wFontSize_t );
+void wDrawClear( wDraw_p );
+
+void wDrawDelayUpdate( wDraw_p, wBool_t );
+void wDrawClip( wDraw_p, wPos_t, wPos_t, wPos_t, wPos_t );
+wDrawColor wDrawColorGray( int );
+wDrawColor wDrawFindColor( long );
+long wDrawGetRGB( wDrawColor );
+
+/* Geometry */
+double wDrawGetDPI( wDraw_p );
+double wDrawGetMaxRadius( wDraw_p );
+void wDrawSetSize( wDraw_p, wPos_t, wPos_t );
+void wDrawGetSize( wDraw_p, wPos_t *, wPos_t * );
+
+/* Bitmaps */
+wDrawBitMap_p wDrawBitMapCreate( wDraw_p, int, int, int, int, const char * );
+void wDrawBitMap( wDraw_p, wDrawBitMap_p, wPos_t, wPos_t,
+ wDrawColor, wDrawOpts );
+
+wDraw_p wBitMapCreate( wPos_t, wPos_t, int );
+wBool_t wBitMapDelete( wDraw_p );
+wBool_t wBitMapWriteFile( wDraw_p, const char * );
+
+/* Misc */
+void * wDrawGetContext( wDraw_p );
+void wDrawSaveImage( wDraw_p );
+void wDrawRestoreImage( wDraw_p );
+
+/*------------------------------------------------------------------------------
+ *
+ * Fonts
+ */
+void wInitializeFonts();
+void wSelectFont( const char * );
+wFontSize_t wSelectedFontSize( void );
+void wSetSelectionFontSize(int);
+#define F_TIMES (1)
+#define F_HELV (2)
+wFont_p wStandardFont( int, wBool_t, wBool_t );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Printing
+ */
+
+typedef void (*wAddPrinterCallBack_p)( const char *, const char * );
+typedef void (*wAddMarginCallBack_p)( const char *, double, double, double, double );
+typedef void (*wAddFontAliasCallBack_p)( const char *, const char * );
+typedef void (*wPrintSetupCallBack_p)( wBool_t );
+
+wBool_t wPrintInit( void );
+void wPrintSetup( wPrintSetupCallBack_p );
+void wPrintSetCallBacks( wAddPrinterCallBack_p, wAddMarginCallBack_p, wAddFontAliasCallBack_p );
+void wPrintGetPageSize( double *, double * );
+void wPrintGetPhysSize( double *, double * );
+wBool_t wPrintDocStart( const char *, int, int * );
+wDraw_p wPrintPageStart( void );
+wBool_t wPrintPageEnd( wDraw_p );
+void wPrintDocEnd( void );
+wBool_t wPrintQuit( void );
+void wPrintClip( wPos_t, wPos_t, wPos_t, wPos_t );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Menus
+ */
+
+#define WACCL_BASE (1000)
+#define WALT (1<<10)
+#define WCTL (1<<11)
+#define WMETA (1<<12)
+#define WSHIFT (1<<13)
+
+typedef enum {
+ wAccelKey_None,
+ wAccelKey_Del,
+ wAccelKey_Ins,
+ wAccelKey_Home,
+ wAccelKey_End,
+ wAccelKey_Pgup,
+ wAccelKey_Pgdn,
+ wAccelKey_Up,
+ wAccelKey_Down,
+ wAccelKey_Right,
+ wAccelKey_Left,
+ wAccelKey_Back,
+ wAccelKey_F1,
+ wAccelKey_F2,
+ wAccelKey_F3,
+ wAccelKey_F4,
+ wAccelKey_F5,
+ wAccelKey_F6,
+ wAccelKey_F7,
+ wAccelKey_F8,
+ wAccelKey_F9,
+ wAccelKey_F10,
+ wAccelKey_F11,
+ wAccelKey_F12 }
+ wAccelKey_e;
+
+/* Creation CallBacks */
+typedef void (*wMenuCallBack_p)( void * );
+typedef void (*wMenuListCallBack_p)( int, const char *, void * );
+typedef void (*wMenuToggleCallBack_p)( wBool_t , void * );
+typedef void (*wAccelKeyCallBack_p)( wAccelKey_e, void * );
+typedef void (*wMenuTraceCallBack_p)( wMenu_p, const char *, void * );
+
+/* Creation Options */
+#define BM_ICON (1L<<0)
+
+wMenu_p wMenuCreate( wWin_p, wPos_t, wPos_t, const char *, const char *, long );
+wMenu_p wMenuBarAdd( wWin_p, const char *, const char * );
+
+wMenuPush_p wMenuPushCreate( wMenu_p, const char *, const char *, long,
+ wMenuCallBack_p, void * );
+wMenuRadio_p wMenuRadioCreate( wMenu_p, const char *, const char *, long,
+ wMenuCallBack_p, void * );
+
+wMenu_p wMenuMenuCreate( wMenu_p, const char *, const char * );
+wMenu_p wMenuPopupCreate( wWin_p, const char * );
+void wMenuSeparatorCreate( wMenu_p );
+wMenuList_p wMenuListCreate( wMenu_p, const char *, int, wMenuListCallBack_p );
+void wMenuRadioSetActive( wMenuRadio_p );
+void wMenuPushEnable( wMenuPush_p, wBool_t );
+void wMenuListAdd( wMenuList_p, int, const char *, const void * );
+void wMenuListDelete( wMenuList_p, const char * );
+const char * wMenuListGet( wMenuList_p, int, void ** );
+void wMenuListClear( wMenuList_p );
+
+wMenuToggle_p wMenuToggleCreate( wMenu_p, const char *, const char *, long, wBool_t, wMenuToggleCallBack_p, void * );
+wBool_t wMenuToggleSet( wMenuToggle_p, wBool_t );
+wBool_t wMenuToggleGet( wMenuToggle_p );
+void wMenuToggleEnable( wMenuToggle_p, wBool_t );
+
+void wMenuPopupShow( wMenu_p );
+
+void wMenuAddHelp( wMenu_p );
+
+void wMenuSetTraceCallBack( wMenu_p, wMenuTraceCallBack_p, void * );
+wBool_t wMenuAction( wMenu_p, const char * );
+
+void wAttachAccelKey( wAccelKey_e, int, wAccelKeyCallBack_p, void * );
+
+/*------------------------------------------------------------------------------
+ *
+ * File Selection
+ */
+
+struct wFilSel_t;
+typedef enum {
+ FS_SAVE,
+ FS_LOAD,
+ FS_UPDATE }
+ wFilSelMode_e;
+typedef int (*wFilSelCallBack_p)( const char * pathName, const char * fileName, void * );
+struct wFilSel_t * wFilSelCreate(wWin_p, wFilSelMode_e, int, const char *, const char *,
+ wFilSelCallBack_p, void * );
+int wFilSelect( struct wFilSel_t *, const char * );
+
+
+/*------------------------------------------------------------------------------
+ *
+ * Color Selection
+ */
+/* Creation CallBacks */
+typedef void (*wColorSelectButtonCallBack_p)( void *, wDrawColor );
+
+wBool_t wColorSelect( const char *, wDrawColor * );
+wButton_p wColorSelectButtonCreate( wWin_p, wPos_t, wPos_t, const char *, const char *,
+ long, wPos_t, wDrawColor *, wColorSelectButtonCallBack_p, void * );
+void wColorSelectButtonSetColor( wButton_p, wDrawColor );
+wDrawColor wColorSelectButtonGetColor( wButton_p );
+
+/*------------------------------------------------------------------------------
+ *
+ * Preferences
+ */
+
+void wPrefSetString( const char *, const char *, const char * );
+const char * wPrefGetString( const char *, const char * );
+void wPrefSetInteger( const char *, const char *, long );
+wBool_t wPrefGetInteger( const char *, const char *, long *, long );
+void wPrefSetFloat( const char *, const char *, double );
+wBool_t wPrefGetFloat( const char *, const char *, double *, double );
+const char * wPrefGetSectionItem( const char * sectionName, wIndex_t * index, const char ** name );
+void wPrefFlush( void );
+void wPrefReset( void );
+
+void CleanupCustom( void );
+
+/*------------------------------------------------------------------------------
+ *
+ * Bitmap Controls
+ */
+
+wControl_p wBitmapCreate( wWin_p parent, wPos_t xx, wPos_t yy, long options, wIcon_p iconP );
+
+#endif
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 &timesFont[bold][italic];
+ else if (family == F_HELV)
+ return &helvFont[bold][italic];
+ else
+ return NULL;
+}
+
+void wSelectFont( const char * title )
+{
+ doChooseFont();
+}
+
+
+wFontSize_t wSelectedFontSize( void )
+{
+ return fontSize;
+}
+
+void wSetSelectedFontSize(int size)
+{
+ fontSize = (wFontSize_t)size;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Misc
+ *
+ *****************************************************************************
+ */
+
+
+
+void wDrawFilledRectangle(
+ wDraw_p d,
+ wPos_t px,
+ wPos_t py,
+ wPos_t sx,
+ wPos_t sy,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ RECT rect;
+ if (d == NULL)
+ return;
+ setDrawBrush( d->hDc, d, color, opts );
+ rect.left = XINCH2PIX(d,px);
+ rect.right = XINCH2PIX(d,px+sx);
+ rect.top = YINCH2PIX(d,py+sy);
+ rect.bottom = YINCH2PIX(d,py);
+ if ( rect.right < 0 ||
+ rect.bottom < 0 )
+ return;
+ if ( rect.left < 0 )
+ rect.left = 0;
+ if ( rect.top < 0 )
+ rect.top = 0;
+ if ( rect.left > d->w ||
+ rect.top > d->h )
+ return;
+ if ( rect.right > d->w )
+ rect.right = d->w;
+ if ( rect.bottom > d->h )
+ rect.bottom = d->h;
+ Rectangle( d->hDc, rect.left, rect.top, rect.right, rect.bottom );
+ if (d->hWnd) {
+ rect.top--;
+ rect.left--;
+ rect.bottom++;
+ rect.right++;
+ myInvalidateRect( d, &rect );
+ }
+}
+
+#ifdef DRAWFILLPOLYLOG
+static FILE * logF;
+#endif
+static int wFillPointsMax = 0;
+static POINT * wFillPoints;
+
+static void addPoint(
+ int * pk,
+ POINT * pp,
+ RECT * pr )
+{
+#ifdef DRAWFILLPOLYLOG
+fprintf( logF, " q[%d] = {%d,%d}\n", *pk, pp->x, pp->y );
+#endif
+ if ( *pk > 0 &&
+ wFillPoints[(*pk)-1].x == pp->x && wFillPoints[(*pk)-1].y == pp->y )
+ return;
+ wFillPoints[ (*pk)++ ] = *pp;
+ if (pp->x<pr->left)
+ pr->left = pp->x;
+ if (pp->x>pr->right)
+ pr->right = pp->x;
+ if (pp->y<pr->top)
+ pr->top = pp->y;
+ if (pp->y>pr->bottom)
+ pr->bottom = pp->y;
+}
+
+void wDrawFilledPolygon(
+ wDraw_p d,
+ wPos_t p[][2],
+ int cnt,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ RECT rect;
+ int i, k;
+ POINT p0, p1, q0, q1;
+ static POINT zero = { 0, 0 };
+ wBool_t p1Clipped;
+
+ if (d == NULL)
+ return;
+ if (cnt*2 > wFillPointsMax) {
+ wFillPoints = realloc( wFillPoints, cnt * 2 * sizeof *(POINT*)NULL );
+ wFillPointsMax = cnt*2;
+ }
+ setDrawBrush( d->hDc, d, color, opts );
+ p1.x = rect.left = rect.right = XINCH2PIX(d,p[cnt-1][0]-1);
+ p1.y = rect.top = rect.bottom = YINCH2PIX(d,p[cnt-1][1]+1);
+#ifdef DRAWFILLPOLYLOG
+logF = fopen( "log.txt", "a" );
+fprintf( logF, "\np[%d] = {%d,%d}\n", cnt-1, p1.x, p1.y );
+#endif
+ p1Clipped = FALSE;
+ for ( i=k=0; i<cnt; i++ ) {
+ p0 = p1;
+ p1.x = XINCH2PIX(d,p[i][0]-1);
+ p1.y = YINCH2PIX(d,p[i][1]+1);
+#ifdef DRAWFILLPOLYLOG
+fprintf( logF, "p[%d] = {%d,%d}\n", i, p1.x, p1.y );
+#endif
+ q0 = p0;
+ q1 = p1;
+ if ( clip0( &q0, &q1, NULL ) ) {
+#ifdef DRAWFILLPOLYLOG
+fprintf( logF, " clip( {%d,%d} {%d,%d} ) = {%d,%d} {%d,%d}\n", p0.x, p0.y, p1.x, p1.y, q0.x, q0.y, q1.x, q1.y );
+#endif
+ if ( q0.x != p0.x || q0.y != p0.y ) {
+ if ( k > 0 && ( q0.x > q0.y ) != ( wFillPoints[k-1].x > wFillPoints[k-1].y ) )
+ addPoint( &k, &zero, &rect );
+ addPoint( &k, &q0, &rect );
+ }
+ addPoint( &k, &q1, &rect );
+ p1Clipped = ( q1.x != p1.x || q1.y != p1.y );
+ }
+ }
+ if ( p1Clipped &&
+ ( wFillPoints[k-1].x > wFillPoints[k-1].y ) != ( wFillPoints[0].x > wFillPoints[0].y ) )
+ addPoint( &k, &zero, &rect );
+#ifdef DRAWFILLPOLYLOG
+fflush( logF );
+fclose( logF );
+#endif
+ if ( k <= 2 )
+ return;
+ Polygon( d->hDc, wFillPoints, k );
+ if (d->hWnd) {
+ rect.top--;
+ rect.left--;
+ rect.bottom++;
+ rect.right++;
+ myInvalidateRect( d, &rect );
+ }
+}
+
+#define MAX_FILLCIRCLE_POINTS (30)
+void wDrawFilledCircle(
+ wDraw_p d,
+ wPos_t x,
+ wPos_t y,
+ wPos_t r,
+ wDrawColor color,
+ wDrawOpts opts )
+{
+ POINT p0, p1;
+ RECT rect;
+ static wPos_t circlePts[MAX_FILLCIRCLE_POINTS][2];
+ int inx, cnt;
+ double dang;
+
+ p0.x = XINCH2PIX(d,x-r);
+ p0.y = YINCH2PIX(d,y+r)+1;
+ p1.x = XINCH2PIX(d,x+r);
+ p1.y = YINCH2PIX(d,y-r)+1;
+
+ setDrawBrush( d->hDc, d, color, opts );
+ if ( noNegDrawArgs > 0 && ( p0.x < 0 || p0.y < 0 ) ) {
+ if ( r > MAX_FILLCIRCLE_POINTS )
+ cnt = MAX_FILLCIRCLE_POINTS;
+ else if ( r > 8 )
+ cnt = r;
+ else
+ cnt = 8;
+ dang = 360.0/cnt;
+ for ( inx=0; inx<cnt; inx++ ) {
+ circlePts[inx][0] = x + (int)(r * mswcos( inx*dang ) + 0.5 );
+ circlePts[inx][1] = y + (int)(r * mswsin( inx*dang ) + 0.5 );
+ }
+ wDrawFilledPolygon( d, circlePts, cnt, color, opts );
+ } else {
+ Ellipse( d->hDc, p0.x, p0.y, p1.x, p1.y );
+ if (d->hWnd) {
+ rect.top = p0.y;
+ rect.bottom = p1.y;
+ rect.left = p0.x;
+ rect.right = p1.x;
+ myInvalidateRect( d, &rect );
+ }
+ }
+}
+
+/*
+ *****************************************************************************
+ *
+ * Misc
+ *
+ *****************************************************************************
+ */
+
+
+void wDrawSaveImage(
+ wDraw_p bd )
+{
+ if ( bd->hBmBackup ) {
+ SelectObject( bd->hDcBackup, bd->hBmBackupOld );
+ DeleteObject( bd->hBmBackup );
+ bd->hBmBackup = (HBITMAP)0;
+ }
+ if ( bd->hDcBackup == (HDC)0 )
+ bd->hDcBackup = CreateCompatibleDC( bd->hDc );
+ bd->hBmBackup = CreateCompatibleBitmap( bd->hDc, bd->w, bd->h );
+ bd->hBmBackupOld = SelectObject( bd->hDcBackup, bd->hBmBackup );
+ BitBlt( bd->hDcBackup, 0, 0, bd->w, bd->h, bd->hDc, 0, 0, SRCCOPY );
+}
+
+void wDrawRestoreImage(
+ wDraw_p bd )
+{
+ if ( bd->hBmBackup == (HBITMAP)0 ) {
+ mswFail( "wDrawRestoreImage: hBmBackup == 0" );
+ return;
+ }
+ BitBlt( bd->hDc, 0, 0, bd->w, bd->h, bd->hDcBackup, 0, 0, SRCCOPY );
+ InvalidateRect( bd->hWnd, NULL, FALSE );
+}
+
+
+void wDrawClear( wDraw_p d )
+{
+ RECT rect;
+ SetROP2( d->hDc, R2_WHITE );
+ Rectangle( d->hDc, 0, 0, d->w, d->h );
+ if (d->hWnd) {
+ rect.top = 0;
+ rect.bottom = d->h;
+ rect.left = 0;
+ rect.right = d->w;
+ InvalidateRect( d->hWnd, &rect, FALSE );
+ }
+}
+
+
+void wDrawSetSize(
+ wDraw_p d,
+ wPos_t width,
+ wPos_t height )
+{
+ d->w = width;
+ d->h = height;
+ if (!SetWindowPos( d->hWnd, HWND_TOP, 0, 0,
+ d->w, d->h, SWP_NOMOVE|SWP_NOZORDER)) {
+ mswFail("wDrawSetSize: SetWindowPos");
+ }
+ /*wRedraw( d );*/
+}
+
+
+void wDrawGetSize(
+ wDraw_p d,
+ wPos_t * width,
+ wPos_t * height )
+{
+ *width = d->w-2;
+ *height = d->h-2;
+}
+
+
+void * wDrawGetContext( wDraw_p d )
+{
+ return d->data;
+}
+
+
+double wDrawGetDPI( wDraw_p d )
+{
+ return d->DPI;
+}
+
+double wDrawGetMaxRadius( wDraw_p d )
+{
+ return 4096.0;
+}
+
+void wDrawClip(
+ wDraw_p d,
+ wPos_t x,
+ wPos_t y,
+ wPos_t w,
+ wPos_t h )
+{
+ int ix0, iy0, ix1, iy1;
+ HRGN hRgnClip;
+ ix0 = XINCH2PIX(d,x);
+ iy0 = YINCH2PIX(d,y);
+ ix1 = XINCH2PIX(d,x+w);
+ iy1 = YINCH2PIX(d,y+h);
+ /* Note: Ydim is upside down so iy1<iy0 */
+ hRgnClip = CreateRectRgn( ix0, iy1, ix1, iy0 );
+ SelectClipRgn( d->hDc, hRgnClip );
+ DeleteObject( hRgnClip );
+}
+
+
+void wRedraw( wDraw_p d )
+{
+ wDrawClear( d );
+ if (d->drawRepaint)
+ d->drawRepaint( d, d->data, 0, 0 );
+}
+
+/*
+ *****************************************************************************
+ *
+ * BitMap
+ *
+ *****************************************************************************
+ */
+
+struct wDrawBitMap_t {
+ wDrawBitMap_p next;
+ wPos_t x;
+ wPos_t y;
+ wPos_t w;
+ wPos_t h;
+ char * bmx;
+ wDrawColor color;
+ HBITMAP bm;
+ };
+wDrawBitMap_p bmRoot = NULL;
+
+
+void wDrawBitMap(
+ wDraw_p d,
+ wDrawBitMap_p bm,
+ wPos_t px,
+ wPos_t py,
+ wDrawColor dc,
+ wDrawOpts dopt )
+{
+ HDC bmDc, hDc;
+ HBITMAP oldBm;
+ DWORD mode;
+ int x0, y0;
+ RECT rect;
+
+ x0 = XINCH2PIX(d,px-bm->x);
+ y0 = YINCH2PIX(d,py-bm->y+bm->h);
+#ifdef LATER
+ if ( noNegDrawArgs > 0 && ( x0 < 0 || y0 < 0 ) )
+ return;
+#endif
+ if (dopt & wDrawOptTemp) {
+ mode = tmpOp;
+ } else if (dc == wDrawColorWhite) {
+ mode = clrOp;
+ dc = wDrawColorBlack;
+ } else {
+ mode = setOp;
+ }
+
+ if ( bm->color != dc ) {
+ if ( bm->bm )
+ DeleteObject( bm->bm );
+ bm->bm = mswCreateBitMap( mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/, RGB( 255, 255, 255 ),
+ RGB( 255, 255, 255 ), bm->w, bm->h, bm->bmx );
+ bm->color = dc;
+ }
+ if ( (dopt & wDrawOptNoClip) != 0 &&
+ ( px < 0 || px >= d->w || py < 0 || py >= d->h ) ) {
+ x0 += d->x;
+ y0 += d->y;
+ hDc = GetDC( ((wControl_p)(d->parent))->hWnd );
+ bmDc = CreateCompatibleDC( hDc );
+ oldBm = SelectObject( bmDc, bm->bm );
+ BitBlt( hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, tmpOp );
+ SelectObject( bmDc, oldBm );
+ DeleteDC( bmDc );
+ ReleaseDC( ((wControl_p)(d->parent))->hWnd, hDc );
+ return;
+ }
+
+ bmDc = CreateCompatibleDC( d->hDc );
+ setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt );
+ oldBm = SelectObject( bmDc, bm->bm );
+ BitBlt( d->hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, mode );
+ SelectObject( bmDc, oldBm );
+ DeleteDC( bmDc );
+ if (d->hWnd) {
+ rect.top = y0-1;
+ rect.bottom = rect.top+bm->h+1;
+ rect.left = x0-1;
+ rect.right = rect.left+bm->w+1;
+ myInvalidateRect( d, &rect );
+ }
+}
+
+
+wDrawBitMap_p wDrawBitMapCreate(
+ wDraw_p d,
+ int w,
+ int h,
+ int x,
+ int y,
+ const char * bits )
+{
+ wDrawBitMap_p bm;
+ int bmSize = ((w+7)/8) * h;
+ bm = (wDrawBitMap_p)malloc( sizeof *bm );
+ if (bmRoot == NULL) {
+ bmRoot = bm;
+ bm->next = NULL;
+ } else {
+ bm->next = bmRoot;
+ bmRoot = bm;
+ }
+ bm->x = x;
+ bm->y = y;
+ bm->w = w;
+ bm->h = h;
+ bm->bmx = malloc( bmSize );
+ bm->bm = (HBITMAP)0;
+ bm->color = -1;
+ memcpy( bm->bmx, bits, bmSize );
+ /*bm->bm = mswCreateBitMap( GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), w, h, bits );*/
+ return bm;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Create
+ *
+ *****************************************************************************
+ */
+
+int doSetFocus = 1;
+
+long FAR PASCAL XEXPORT mswDrawPush(
+ HWND hWnd,
+ UINT message,
+ UINT wParam,
+ LONG lParam )
+{
+#ifdef WIN32
+ long inx = GetWindowLong( hWnd, GWL_ID );
+#else
+ short inx = GetWindowWord( hWnd, GWW_ID );
+#endif
+ wDraw_p b;
+ short int ix, iy;
+ wPos_t x, y;
+ HDC hDc;
+ PAINTSTRUCT ps;
+ wAction_t action;
+ RECT rect;
+ HWND activeWnd;
+ HWND focusWnd;
+ wAccelKey_e extChar;
+
+ switch( message ) {
+ case WM_CREATE:
+ b = (wDraw_p)mswMapIndex( inx );
+ hDc = GetDC(hWnd);
+ if ( b->option & BD_DIRECT ) {
+ b->hDc = hDc;
+ b->hBm = 0;
+ b->hBmOld = 0;
+ } else {
+ b->hDc = CreateCompatibleDC( hDc );
+ b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h );
+ b->hBmOld = SelectObject( b->hDc, b->hBm );
+ }
+ if (mswPalette) {
+ SelectPalette( b->hDc, mswPalette, 0 );
+ RealizePalette( b->hDc );
+ }
+ b->wFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSX );
+ b->hFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSY );
+ b->DPI = 96.0; /*min( b->wFactor, b->hFactor );*/
+ b->hWnd = hWnd;
+ SetROP2( b->hDc, R2_WHITE );
+ Rectangle( b->hDc, 0, 0, b->w, b->h );
+ if ( (b->option & BD_DIRECT) == 0 ) {
+ SetROP2( hDc, R2_WHITE );
+ Rectangle( hDc, 0, 0, b->w, b->h );
+ ReleaseDC( hWnd, hDc );
+ }
+ break;
+ case WM_SIZE:
+ b = (wDraw_p)mswMapIndex( inx );
+ ix = LOWORD( lParam );
+ iy = HIWORD( lParam );
+ b->w = ix+2;
+ b->h = iy+2;
+ if (b->hWnd) {
+ if ( b->option & BD_DIRECT ) {
+ } else {
+ hDc = GetDC( b->hWnd );
+ b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h );
+ DeleteObject(SelectObject( b->hDc, b->hBm ));
+ ReleaseDC( b->hWnd, hDc );
+ SetROP2( b->hDc, R2_WHITE );
+ Rectangle( b->hDc, 0, 0, b->w, b->h );
+ }
+ }
+ /*if (b->drawResize)
+ b->drawResize( b, b->size );*/
+ if (b->drawRepaint)
+ b->drawRepaint( b, b->data, 0, 0 );
+ return 0;
+ case WM_MOUSEMOVE:
+ activeWnd = GetActiveWindow();
+ focusWnd = GetFocus();
+ if (focusWnd != hWnd) {
+ b = (wDraw_p)mswMapIndex( inx );
+ if (!b)
+ break;
+ if ( !((wControl_p)b->parent) )
+ break;
+ if ( ((wControl_p)b->parent)->hWnd != activeWnd )
+ break;
+ }
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ if (message == WM_LBUTTONDOWN)
+ action = wActionLDown;
+ else if (message == WM_RBUTTONDOWN)
+ action = wActionRDown;
+ else if (message == WM_LBUTTONUP)
+ action = wActionLUp;
+ else if (message == WM_RBUTTONUP)
+ action = wActionRUp;
+ else {
+ if ( (wParam & MK_LBUTTON) != 0)
+ action = wActionLDrag;
+ else if ( (wParam & MK_RBUTTON) != 0)
+ action = wActionRDrag;
+ else
+ action = wActionMove;
+ }
+ b = (wDraw_p)mswMapIndex( inx );
+ if (!b)
+ break;
+ if (doSetFocus && message != WM_MOUSEMOVE)
+ SetFocus( ((wControl_p)b->parent)->hWnd );
+ if ( (b->option&BD_NOCAPTURE) == 0 ) {
+ if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN)
+ SetCapture( b->hWnd );
+ else if (message == WM_LBUTTONUP || message == WM_RBUTTONUP)
+ ReleaseCapture();
+ }
+ ix = LOWORD( lParam );
+ iy = HIWORD( lParam );
+ x = XPIX2INCH( b, ix );
+ y = YPIX2INCH( b, iy );
+ if (b->action)
+ b->action( b, b->data, action, x, y );
+ if (b->hWnd)
+ UpdateWindow(b->hWnd);
+ return 0;
+ case WM_CHAR:
+ b = (wDraw_p)mswMapIndex( inx );
+ extChar = wAccelKey_None;
+ if (lParam & 0x01000000L)
+ switch( wParam ) {
+ case VK_DELETE: extChar = wAccelKey_Del; break;
+ case VK_INSERT: extChar = wAccelKey_Ins; break;
+ case VK_HOME: extChar = wAccelKey_Home; break;
+ case VK_END: extChar = wAccelKey_End; break;
+ case VK_PRIOR: extChar = wAccelKey_Pgup; break;
+ case VK_NEXT: extChar = wAccelKey_Pgdn; break;
+ case VK_UP: extChar = wAccelKey_Up; break;
+ case VK_DOWN: extChar = wAccelKey_Down; break;
+ case VK_RIGHT: extChar = wAccelKey_Right; break;
+ case VK_LEFT: extChar = wAccelKey_Left; break;
+ case VK_BACK: extChar = wAccelKey_Back; break;
+ /*case VK_F1: extChar = wAccelKey_F1; break;*/
+ case VK_F2: extChar = wAccelKey_F2; break;
+ case VK_F3: extChar = wAccelKey_F3; break;
+ case VK_F4: extChar = wAccelKey_F4; break;
+ case VK_F5: extChar = wAccelKey_F5; break;
+ case VK_F6: extChar = wAccelKey_F6; break;
+ case VK_F7: extChar = wAccelKey_F7; break;
+ case VK_F8: extChar = wAccelKey_F8; break;
+ case VK_F9: extChar = wAccelKey_F9; break;
+ case VK_F10: extChar = wAccelKey_F10; break;
+ case VK_F11: extChar = wAccelKey_F11; break;
+ case VK_F12: extChar = wAccelKey_F12; break;
+ }
+ if (b && b->action) {
+ if (extChar != wAccelKey_None)
+ b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), 0, 0 );
+ else
+ b->action( b, b->data, wActionText + ( wParam << 8 ), 0, 0 );
+ }
+ return 0;
+
+ case WM_PAINT:
+ b = (wDraw_p)mswMapIndex( inx );
+ if (b && b->type == B_DRAW) {
+ if (GetUpdateRect( b->hWnd, &rect, FALSE )) {
+ hDc = BeginPaint( hWnd, &ps );
+ if ( b->hasPalette ) {
+ int winPaletteClock = mswGetPaletteClock();
+ if ( b->paletteClock < winPaletteClock ) {
+ RealizePalette( hDc );
+ b->paletteClock = winPaletteClock;
+ }
+ }
+ BitBlt( hDc, rect.left, rect.top,
+ rect.right-rect.left, rect.bottom-rect.top,
+ b->hDc, rect.left, rect.top,
+ SRCCOPY );
+ EndPaint( hWnd, &ps );
+ }
+ }
+ break;
+ case WM_DESTROY:
+ b = (wDraw_p)mswMapIndex( inx );
+ if (b && b->type == B_DRAW) {
+ if (b->hDc) {
+ DeleteDC( b->hDc );
+ b->hDc = (HDC)0;
+ }
+ if (b->hDcBackup) {
+ DeleteDC( b->hDcBackup );
+ b->hDcBackup = (HDC)0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return DefWindowProc( hWnd, message, wParam, lParam );
+}
+
+
+static LRESULT drawMsgProc( wDraw_p b, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+ wAction_t action;
+
+ switch( message ) {
+ case WM_MOUSEWHEEL:
+ /* handle mouse wheel events */
+ /* fwKeys = GET_KEYSTATE_WPARAM(wParam); modifier keys are currently ignored */
+ if ( GET_WHEEL_DELTA_WPARAM(wParam) > 0 ) {
+ action = wActionWheelUp;
+ } else {
+ action = wActionWheelDown;
+ }
+ if (b->action)
+ b->action( b, b->data, action, 0, 0 );
+ return 0;
+ }
+
+ return DefWindowProc( hWnd, message, wParam, lParam );
+}
+
+
+static void drawDoneProc( wControl_p b )
+{
+ wDraw_p d = (wDraw_p)b;
+ if (d->hBm) {
+ SelectObject( d->hDc, d->hBmOld );
+ DeleteObject( d->hBm );
+ d->hBm = (HBITMAP)0;
+ }
+ if (d->hPen) {
+ SelectObject( d->hDc, GetStockObject( BLACK_PEN ) );
+ DeleteObject( d->hPen );
+ d->hPen = (HPEN)0;
+ }
+ if (d->hBrush) {
+ SelectObject( d->hDc, GetStockObject( BLACK_BRUSH) );
+ DeleteObject( d->hBrush );
+ d->hBrush = (HBRUSH)0;
+ }
+ if (d->hDc) {
+ DeleteDC( d->hDc );
+ d->hDc = (HDC)0;
+ }
+ if ( d->hDcBackup ) {
+ DeleteDC( d->hDcBackup );
+ d->hDcBackup = (HDC)0;
+ }
+ while (bmRoot) {
+ if (bmRoot->bm)
+ DeleteObject( bmRoot->bm );
+ bmRoot = bmRoot->next;
+ }
+}
+
+
+static callBacks_t drawCallBacks = {
+ NULL,
+ drawDoneProc,
+ (messageCallback_p)drawMsgProc };
+
+wDraw_p drawList = NULL;
+
+
+void mswRedrawAll( void )
+{
+ wDraw_p p;
+ for ( p=drawList; p; p=p->drawNext ) {
+ if (p->drawRepaint)
+ p->drawRepaint( p, p->data, 0, 0 );
+ }
+}
+
+
+void mswRepaintAll( void )
+{
+ wDraw_p b;
+ HDC hDc;
+ RECT rect;
+ PAINTSTRUCT ps;
+
+ for ( b=drawList; b; b=b->drawNext ) {
+ if (GetUpdateRect( b->hWnd, &rect, FALSE )) {
+ hDc = BeginPaint( b->hWnd, &ps );
+ BitBlt( hDc, rect.left, rect.top,
+ rect.right-rect.left, rect.bottom-rect.top,
+ b->hDc, rect.left, rect.top,
+ SRCCOPY );
+ EndPaint( b->hWnd, &ps );
+ }
+ }
+}
+
+
+wDraw_p wDrawCreate(
+ wWin_p parent,
+ wPos_t x,
+ wPos_t y,
+ const char * helpStr,
+ long option,
+ wPos_t w,
+ wPos_t h,
+ void * data,
+ wDrawRedrawCallBack_p redrawProc,
+ wDrawActionCallBack_p action )
+{
+ wDraw_p d;
+ RECT rect;
+ int index;
+ HDC hDc;
+
+ if ( noNegDrawArgs < 0 ) {
+ wPrefGetInteger( "msw tweak", "NoNegDrawArgs", &noNegDrawArgs, 0 );
+ wPrefGetInteger( "msw tweak", "NoFlatEndCaps", &noFlatEndCaps, 0 );
+ }
+
+ d = mswAlloc( parent, B_DRAW, NULL, sizeof *d, data, &index );
+ mswComputePos( (wControl_p)d, x, y );
+ d->w = w;
+ d->h = h;
+ d->drawRepaint = NULL;
+ d->action = action;
+ d->option = option;
+
+ d->hWnd = CreateWindow( mswDrawWindowClassName, NULL,
+ WS_CHILDWINDOW|WS_VISIBLE|WS_BORDER,
+ d->x, d->y, w, h,
+ ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL );
+
+ if (d->hWnd == (HWND)0) {
+ mswFail( "CreateWindow(DRAW)" );
+ return d;
+ }
+
+ GetWindowRect( d->hWnd, &rect );
+
+ d->w = rect.right - rect.left;
+ d->h = rect.bottom - rect.top;
+ d->drawRepaint = redrawProc;
+ /*if (d->drawRepaint)
+ d->drawRepaint( d, d->data, 0.0, 0.0 );*/
+
+ mswAddButton( (wControl_p)d, FALSE, helpStr );
+ mswCallBacks[B_DRAW] = &drawCallBacks;
+ d->drawNext = drawList;
+ drawList = d;
+ if (mswPalette) {
+ hDc = GetDC( d->hWnd );
+ d->hasPalette = TRUE;
+ SelectPalette( hDc, mswPalette, 0 );
+ ReleaseDC( d->hWnd, hDc );
+ }
+ return d;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Bitmaps
+ *
+ *****************************************************************************
+ */
+
+wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes )
+{
+ wDraw_p d;
+ HDC hDc;
+
+ d = (wDraw_p)calloc(1,sizeof *d);
+ d->type = B_DRAW;
+ d->shown = TRUE;
+ d->x = 0;
+ d->y = 0;
+ d->w = w;
+ d->h = h;
+ d->drawRepaint = NULL;
+ d->action = NULL;
+ d->option = 0;
+
+ hDc = GetDC(mswHWnd);
+ d->hDc = CreateCompatibleDC( hDc );
+ if ( d->hDc == (HDC)0 ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: CreateDC fails", "Ok", NULL );
+ return FALSE;
+ }
+ d->hBm = CreateCompatibleBitmap( hDc, d->w, d->h );
+ if ( d->hBm == (HBITMAP)0 ) {
+ wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM fails", "Ok", NULL );
+ return FALSE;
+ }
+ d->hasPalette = (GetDeviceCaps(hDc,RASTERCAPS ) & RC_PALETTE) != 0;
+ ReleaseDC( mswHWnd, hDc );
+ d->hBmOld = SelectObject( d->hDc, d->hBm );
+ if (mswPalette) {
+ SelectPalette( d->hDc, mswPalette, 0 );
+ RealizePalette( d->hDc );
+ }
+ d->wFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSX );
+ d->hFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSY );
+ d->DPI = 96.0; /*min( d->wFactor, d->hFactor );*/
+ d->hWnd = 0;
+ SetROP2( d->hDc, R2_WHITE );
+ Rectangle( d->hDc, 0, 0, d->w, d->h );
+ return d;
+}
+
+wBool_t wBitMapDelete( wDraw_p d )
+{
+ if (d->hPen) {
+ SelectObject( d->hDc, GetStockObject( BLACK_PEN ) );
+ DeleteObject( d->hPen );
+ d->hPen = (HPEN)0;
+ }
+ if (d->hBm) {
+ SelectObject( d->hDc, d->hBmOld );
+ DeleteObject( d->hBm );
+ d->hBm = (HBITMAP)0;
+ }
+ if (d->hDc) {
+ DeleteDC( d->hDc );
+ d->hDc = (HDC)0;
+ }
+ free(d);
+ return TRUE;
+}
+
+wBool_t wBitMapWriteFile( wDraw_p d, const char * fileName )
+{
+ char *pixels;
+ int j, ww, chunk;
+ FILE * f;
+ BITMAPFILEHEADER bmfh;
+ struct {
+ BITMAPINFOHEADER bmih;
+ RGBQUAD colors[256];
+ } bmi;
+ int rc;
+
+ if ( d->hBm == 0)
+ return FALSE;
+ f = wFileOpen( fileName, "wb" );
+ if (!f) {
+ wNoticeEx( NT_ERROR, fileName, "Ok", NULL );
+ return FALSE;
+ }
+ ww = ((d->w +3) / 4) * 4;
+ bmfh.bfType = 'B'+('M'<<8);
+ bmfh.bfSize = (long)(sizeof bmfh) + (long)(sizeof bmi.bmih) + (long)(sizeof bmi.colors) + (long)ww * (long)(d->h);
+ bmfh.bfReserved1 = 0;
+ bmfh.bfReserved2 = 0;
+ bmfh.bfOffBits = sizeof bmfh + sizeof bmi.bmih + sizeof bmi.colors;
+ fwrite( &bmfh, 1, sizeof bmfh, f );
+ bmi.bmih.biSize = sizeof bmi.bmih;
+ bmi.bmih.biWidth = d->w;
+ bmi.bmih.biHeight = d->h;
+ bmi.bmih.biPlanes = 1;
+ bmi.bmih.biBitCount = 8;
+ bmi.bmih.biCompression = BI_RGB;
+ bmi.bmih.biSizeImage = 0;
+ bmi.bmih.biXPelsPerMeter = 75*(10000/254);
+ bmi.bmih.biYPelsPerMeter = 75*(10000/254);
+ bmi.bmih.biClrUsed = bmi.bmih.biClrImportant = mswGetColorList( bmi.colors );
+ SelectObject( d->hDc, d->hBmOld );
+ rc = GetDIBits( d->hDc, d->hBm, 0, 1, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS );
+ if ( rc == 0 ) {
+ wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bitmapinfo from Bitmap", "Ok", NULL );
+ return FALSE;
+ }
+ bmi.bmih.biClrUsed = 256;
+ fwrite( &bmi.bmih, 1, sizeof bmi.bmih, f );
+ fwrite( bmi.colors, 1, sizeof bmi.colors, f );
+ chunk = 32000/ww;
+ pixels = (char*)malloc( ww*chunk );
+ if ( pixels == NULL ) {
+ wNoticeEx( NT_ERROR, "WriteBitMap: no memory", "OK", NULL );
+ return FALSE;
+ }
+ for (j=0;j<d->h;j+=chunk) {
+ if (j+chunk>d->h)
+ chunk = d->h-j;
+ rc = GetDIBits( d->hDc, d->hBm, j, chunk, pixels, (BITMAPINFO*)&bmi, DIB_RGB_COLORS );
+ if ( rc == 0 )
+ if ( rc == 0 ) {
+ wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bits from Bitmap", "Ok", NULL );
+ return FALSE;
+ }
+ rc = fwrite( pixels, 1, ww*chunk, f );
+ if (rc != ww*chunk) {
+ wNoticeEx( NT_ERROR, "WriteBitMap: Bad fwrite", "Ok", NULL);
+ }
+ }
+ free( pixels );
+ SelectObject( d->hDc, d->hBm );
+ fclose( f );
+ return TRUE;
+}
+
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};
diff --git a/app/wlib/test/alarmtst.c b/app/wlib/test/alarmtst.c
new file mode 100644
index 0000000..da11c91
--- /dev/null
+++ b/app/wlib/test/alarmtst.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include "wlib.h"
+
+
+#define TRUE (1)
+#define FALSE (0)
+
+wMessage_p msgP;
+int ticks;
+char tickM[40] = "INIT";
+int alarmCont = 0;
+
+void tick( void )
+{
+ sprintf( tickM, "%d", ticks++ );
+ wMessageSetValue( msgP, tickM );
+ if (alarmCont)
+ wAlarm( 1000, tick );
+}
+
+
+void doCmd( void * cmd )
+{
+ int i;
+ switch ((int)cmd) {
+ case 1:
+ alarmCont = 1;
+ wAlarm( 1000, tick );
+ break;
+ case 2:
+ for (i=0; i<10; i++ ) {
+ sprintf( tickM, "%d", ticks++ );
+ wMessageSetValue( msgP, tickM );
+ wPause( 1000 );
+ }
+ break;
+ case 3:
+ alarmCont = 0;
+ break;
+ case 4:
+ wExit( 0 );
+ }
+}
+
+wWin_p wMain( int argc, char * argv[] )
+{
+
+ wWin_p mainW;
+ wMenu_p m;
+
+ mainW = wWinMainCreate( "Fred", 60, 40, "Help", "Main", "", F_MENUBAR, NULL, NULL );
+ m = wMenuBarAdd( mainW, NULL, "Cmd" );
+ wMenuPushCreate( m, NULL, "Alarm", 0, doCmd, (void*)1 );
+ wMenuPushCreate( m, NULL, "Pause", 0, doCmd, (void*)2 );
+ wMenuPushCreate( m, NULL, "Stop", 0, doCmd, (void*)3 );
+ wMenuPushCreate( m, NULL, "Exit", 0, doCmd, (void*)4 );
+ msgP = wMessageCreate( mainW, 2, 2, NULL, 40, tickM );
+ return mainW;
+}
diff --git a/app/wlib/test/alarmtst.mak b/app/wlib/test/alarmtst.mak
new file mode 100644
index 0000000..771a988
--- /dev/null
+++ b/app/wlib/test/alarmtst.mak
@@ -0,0 +1,2 @@
+all:
+ nmake /f wtest.mak TEST=alarmtst
diff --git a/app/wlib/test/bits.bmp b/app/wlib/test/bits.bmp
new file mode 100644
index 0000000..2d36fad
--- /dev/null
+++ b/app/wlib/test/bits.bmp
@@ -0,0 +1,6 @@
+#define bits_width 16
+#define bits_height 16
+static char bits_bits[] = {
+ 0x00, 0xc0, 0xb2, 0xc0, 0xe6, 0x72, 0x60, 0x38, 0x16, 0x00, 0x10, 0x00,
+ 0xe4, 0x44, 0x28, 0x02, 0x12, 0x44, 0x12, 0x80, 0x22, 0x02, 0x22, 0x40,
+ 0x12, 0xc8, 0x0e, 0x82, 0x00, 0x12, 0xc0, 0x01};
diff --git a/app/wlib/test/boxtest.c b/app/wlib/test/boxtest.c
new file mode 100644
index 0000000..6cb5631
--- /dev/null
+++ b/app/wlib/test/boxtest.c
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "wlib.h"
+
+#define TRUE (1)
+
+wWin_p mainW;
+
+int tests = 255;
+
+wWin_p wMain( int argc, char * argv[] )
+{
+ mainW = wWinMainCreate( "drawtest", 300, 300, NULL, "Main", "Main", F_RESIZE, NULL, NULL );
+ if (tests & 0x01)
+ wBoxCreate( mainW, 10, 10, NULL, wBoxThinB, 280, 280 );
+ if (tests & 0x02)
+ wBoxCreate( mainW, 20, 20, NULL, wBoxThinW, 260, 260 );
+ if (tests & 0x04)
+ wBoxCreate( mainW, 30, 30, NULL, wBoxAbove, 240, 240 );
+ if (tests & 0x08)
+ wBoxCreate( mainW, 40, 40, NULL, wBoxBelow, 220, 220 );
+ if (tests & 0x10)
+ wBoxCreate( mainW, 50, 50, NULL, wBoxThickB, 200, 200 );
+ if (tests & 0x20)
+ wBoxCreate( mainW, 60, 60, NULL, wBoxThickW, 180, 180 );
+ if (tests & 0x40)
+ wBoxCreate( mainW, 70, 70, NULL, wBoxRidge, 160, 160 );
+ if (tests & 0x80)
+ wBoxCreate( mainW, 80, 80, NULL, wBoxTrough, 140, 140 );
+ return mainW;
+}
diff --git a/app/wlib/test/boxtest.mak b/app/wlib/test/boxtest.mak
new file mode 100644
index 0000000..799f9f1
--- /dev/null
+++ b/app/wlib/test/boxtest.mak
@@ -0,0 +1,2 @@
+all:
+ nmake /f wtest.mak TEST=boxtest
diff --git a/app/wlib/test/btest.c b/app/wlib/test/btest.c
new file mode 100644
index 0000000..6042229
--- /dev/null
+++ b/app/wlib/test/btest.c
@@ -0,0 +1,212 @@
+#include <stdio.h>
+#include <stdlib.h>
+/*#include "common.h"*/
+/*#include "utility.h"*/
+#include "wlib.h"
+#include "dtest.bmp"
+#include "bits.bmp"
+
+#define TRUE (1)
+#define FALSE (0)
+
+ wWin_p mainW;
+ wMenu_p m00, m01, m02;
+ wWin_p w1, w2, w3, w4, w5, w6, w7, w8;
+ wDraw_p d[9];
+ wMenu_p m3, m4, m7, m8;
+ wText_p txt;
+wBool_t doresize = FALSE;
+
+static void doExit( void * data )
+{
+ wExit(0);
+}
+
+/*static void doFont( void * data )
+{
+ char * f;
+ wSelectFont();
+ f = wCurFont();
+ wMessage( w5, f, FALSE );
+}*/
+
+
+static void doRestore( void * data )
+{
+ wDraw_p d = (wDraw_p) data;
+ wDrawSetSize( d, 200, 200 );
+}
+
+
+static void mainEvent( wWin_p w, winProcEvent e, void * data )
+{
+ wPos_t width, height;
+ switch( e ) {
+ case wResize_e:
+ wWinGetSize( w, &width, &height );
+ wTextSetSize( txt, width, height );
+ break;
+ default:
+ ;
+ }
+}
+
+static void winEvent( wWin_p w, winProcEvent e, void * data )
+{
+ wPos_t width, height;
+ wIndex_t inx;
+ char msg[80];
+ switch( e ) {
+ case wResize_e:
+ inx = (wIndex_t)data;
+ wWinGetSize( w, &width, &height );
+ sprintf( msg, "%s: %d x %d\n", wWinGetTitle(w), width, height );
+ wTextAppend( txt, msg );
+ if ( doresize)
+ wDrawSetSize( d[inx], width-4, height-4 );
+ break;
+ default:
+ ;
+ }
+}
+
+wDrawBitMap_p bm_w8;
+wDrawBitMap_p bm_w4;
+
+void doMouse( wAction_t action, double x, double y )
+{
+ char buff[80];
+ wPos_t ix, iy;
+ ix = x * wDrawGetDPI( d[1] );
+ iy = y * wDrawGetDPI( d[1] );
+ sprintf( buff, "%d: [%0.3f %0.3f] ( %d %d )\n", (int)action, x, y, ix, iy );
+ wTextAppend( txt, buff );
+#ifdef LATER
+ switch ( action ) {
+ case wActionDown:
+
+ wDrawBitMap( d[4], bm_w4, x, y, wDrawColorRed, wDrawOptTemp );
+ oldX = x;
+ oldY = y;
+ break;
+ case wActionMove:
+ wDrawBitMap( d[4], bm_w4, oldX, oldY, wDrawColorRed, wDrawOptTemp );
+ wDrawBitMap( d[4], bm_w4, x, y, wDrawColorRed, wDrawOptTemp );
+ oldX = x;
+ oldY = y;
+ break;
+ case wActionUp:
+ wDrawBitMap( d[4], bm_w4, oldX, oldY, wDrawColorRed, wDrawOptTemp );
+ wDrawBitMap( d[4], bm_w4, x, y, wDrawColorRed, 0 );
+ break;
+ }
+#endif
+}
+
+void doBitMap( wAction_t action, double x, double y )
+{
+ static double oldX, oldY;
+ switch ( action ) {
+ case wActionDown:
+
+ wDrawBitMap( d[4], bm_w4, x, y, wDrawColorRed, wDrawOptTemp );
+ oldX = x;
+ oldY = y;
+ break;
+ case wActionMove:
+ wDrawBitMap( d[4], bm_w4, oldX, oldY, wDrawColorRed, wDrawOptTemp );
+ wDrawBitMap( d[4], bm_w4, x, y, wDrawColorRed, wDrawOptTemp );
+ oldX = x;
+ oldY = y;
+ break;
+ case wActionUp:
+ wDrawBitMap( d[4], bm_w4, oldX, oldY, wDrawColorRed, wDrawOptTemp );
+ wDrawBitMap( d[4], bm_w4, x, y, wDrawColorRed, 0 );
+ break;
+ }
+}
+
+static wLines_t lines[] = {
+ { 0, 2, 2, 198, 2 },
+ { 0, 198, 2, 198, 198 },
+ { 0, 198, 198, 2, 198 },
+ { 0, 2, 198, 2, 2 },
+ { 0, 2, 2, 198, 198 },
+ { 0, 2, 198, 198, 2 } };
+
+wWin_p wMain( int argc, char * argv[] )
+{
+
+ mainW = wWinMainCreate( "dtest", 0, 0, "Help", "Main", F_MENUBAR|F_AUTOSIZE, mainEvent, NULL );
+ wWinSetIcon( mainW, dtest_width, dtest_height, dtest_bits );
+ m00 = wMenuBarAdd( mainW, "menu0-0", "&Restore" );
+ m01 = wMenuBarAdd( mainW, "menu0-1", "&Message" );
+ m02 = wMenuBarAdd( mainW, "menu0-2", "M&isc" );
+ txt = wTextCreate( mainW, 0, 0, NULL, NULL, BT_CHARUNITS, 40, 15 );
+
+ w1 = wWinPopupCreate( mainW, 2, 2, "Help1", "1", F_AUTOSIZE, winEvent, (void*)1 );
+ d[1] = wDrawCreate( w1, 2, 2, "Draw-1", 0, 200, 200, w1, NULL, doMouse );
+ wLineCreate( w1, "", 6, lines );
+
+ w2 = wWinPopupCreate( mainW, 2, 2, "Help2", "2 Resize", F_AUTOSIZE|F_RESIZE, winEvent, (void*)2 );
+ d[2] = wDrawCreate( w2, 2, 2, "Draw-1", 0, 200, 200, w2, NULL, doMouse );
+ wLineCreate( w2, "", 6, lines );
+
+ w3 = wWinPopupCreate( mainW, 2, 2, "Help3", "3 MenuBar", F_AUTOSIZE|F_MENUBAR, winEvent, (void*)3 );
+ d[3] = wDrawCreate( w3, 2, 2, "Draw-3", 0, 200, 200, w3, NULL, doMouse );
+ m3 = wMenuBarAdd( w3, "HelpMB3", "Menu3" );
+ wLineCreate( w3, "", 6, lines );
+
+ w4 = wWinPopupCreate( mainW, 2, 2, "Help4", "4 Resize|MenuBar", F_AUTOSIZE|F_MENUBAR|F_RESIZE, winEvent, (void*)4 );
+ d[4] = wDrawCreate( w4, 2, 2, "Draw-4", 0, 200, 200, w4, NULL, doBitMap );
+ bm_w4 = wDrawBitMapCreate( d[4], bits_width, bits_height, 0, 0, bits_bits );
+ m4 = wMenuBarAdd( w4, "HelpMB4", "Menu4" );
+ wLineCreate( w4, "", 6, lines );
+
+#ifdef LATER
+ w5 = wWinPopupCreate( mainW, 3, 3, "Help5", "5 Footer", F_AUTOSIZE|F_FOOTER, winEvent, (void*)5 );
+ d[5] = wDrawCreate( w5, 2, 2, "Draw-5", 0, 200, 200, w5, NULL, NULL );
+ wLineCreate( w5, "", 6, lines );
+
+ w6 = wWinPopupCreate( mainW, 3, 3, "Help6", "6 Footer|Resize", F_AUTOSIZE|F_FOOTER|F_RESIZE, winEvent, (void*)6 );
+ d[6] = wDrawCreate( w6, 2, 2, "Draw-6", 0, 200, 200, w6, NULL, NULL );
+ wLineCreate( w6, "", 6, lines );
+
+ w7 = wWinPopupCreate( mainW, 3, 3, "Help7", "7 Footer|MenuBar", F_AUTOSIZE|F_FOOTER|F_MENUBAR, winEvent, (void*)7 );
+ d[7] = wDrawCreate( w7, 2, 2, "Draw-7", 0, 200, 200, w7, NULL, NULL );
+ m7 = wMenuBarAdd( w7, "HelpMB7", "Menu7" );
+ wLineCreate( w7, "", 6, lines );
+
+ w8 = wWinPopupCreate( mainW, 3, 3, "Help8", "8 Footer|Resize|MenuBar", F_AUTOSIZE|F_FOOTER|F_MENUBAR|F_RESIZE, winEvent, (void*)8 );
+ d[8] = wDrawCreate( w8, 2, 2, "Draw-8", 0, 200, 200, w8, NULL, doMouse );
+ bm_w8 = wDrawBitMapCreate( d[8], bits_width, bits_height, 0, 0, bits_bits );
+ m8 = wMenuBarAdd( w8, "HelpMB8", "Menu8" );
+ wLineCreate( w8, "", 6, lines );
+#endif
+
+ wMenuPushCreate( m00, "menu0-1", "&1", doRestore, (void*)d[1] );
+ wMenuPushCreate( m00, "menu0-2", "&2", doRestore, (void*)d[2] );
+ wMenuPushCreate( m00, "menu0-3", "&3", doRestore, (void*)d[3] );
+ wMenuPushCreate( m00, "menu0-4", "&4", doRestore, (void*)d[4] );
+ wMenuPushCreate( m00, "menu0-5", "&5", doRestore, (void*)d[5] );
+ wMenuPushCreate( m00, "menu0-6", "&6", doRestore, (void*)d[6] );
+ wMenuPushCreate( m00, "menu0-7", "&7", doRestore, (void*)d[7] );
+ wMenuPushCreate( m00, "menu0-8", "&8", doRestore, (void*)d[8] );
+
+
+ wMenuPushCreate( m02, "menu2-1", "&Exit", doExit, NULL );
+/* wMenuPushCreate( m02, "menu2-2", "&Font", doFont, NULL );*/
+
+ wWinShow( w1, TRUE );
+ wWinShow( w2, TRUE );
+ wWinShow( w3, TRUE );
+ wWinShow( w4, TRUE );
+#ifdef LATER
+ wWinShow( w5, TRUE );
+ wWinShow( w6, TRUE );
+ wWinShow( w7, TRUE );
+ wWinShow( w8, TRUE );
+#endif
+
+ return mainW;
+}
diff --git a/app/wlib/test/btest.mak b/app/wlib/test/btest.mak
new file mode 100644
index 0000000..49db72f
--- /dev/null
+++ b/app/wlib/test/btest.mak
@@ -0,0 +1,2 @@
+all:
+ nmake /f wtest.mak TEST=btest
diff --git a/app/wlib/test/colortst.c b/app/wlib/test/colortst.c
new file mode 100644
index 0000000..2680c23
--- /dev/null
+++ b/app/wlib/test/colortst.c
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "wlib.h"
+
+#define TRUE (1)
+
+wWin_p mainW;
+wDraw_p mainD;
+wWin_p popupW;
+wDraw_p popupD;
+/*wFont_p font;*/
+
+void redrawColor( wDraw_p d, void * context, wPos_t w, wPos_t h )
+{
+ wDrawColor c;
+ wPos_t x0, y0, x1, y1, incr;
+
+ wDrawGetSize( mainD, &w, &h );
+ incr = w / 16;
+ x0 = y0 = 0;
+ x1 = w; y1 = h;
+ for ( c=0; c<=7; c++ ) {
+ /*printf(" color %d - %0.3f,%0.3f - %0.3f,%0.3f\n",
+ c, x0, y0, x1, y1 );*/
+ wDrawLine( d, x0, y0, x1, y0, incr, wDrawLineSolid, c, wDrawOptTemp );
+ wDrawLine( d, x1, y0, x1, y1, incr, wDrawLineSolid, c, wDrawOptTemp );
+ wDrawLine( d, x1, y1, x0, y1, incr, wDrawLineSolid, c, 0 );
+ wDrawLine( d, x0, y1, x0, y0, incr, wDrawLineSolid, c, 0 );
+ x0 += incr;
+ y0 += incr;
+ x1 -= incr;
+ y1 -= incr;
+ }
+}
+
+void redrawGray( wDraw_p d, void * context, wPos_t w, wPos_t h )
+{
+ wDrawColor c;
+ int i;
+ wPos_t x0, y0, x1, y1, incr;
+
+ wDrawGetSize( popupD, &w, &h );
+ incr = w/32;
+ x0 = y0 = 0;
+ x1 = w; y1 = h;
+ for ( i=0; i<=100; i+=6 ) {
+ c = wDrawColorGray( i );
+ /*printf(" color %d - %0.3f,%0.3f - %0.3f,%0.3f\n",
+ c, x0, y0, x1, y1 );*/
+ wDrawLine( d, x0, y0, x1, y0, incr, wDrawLineSolid, c, 0 );
+ wDrawLine( d, x1, y0, x1, y1, incr, wDrawLineSolid, c, 0 );
+ wDrawLine( d, x1, y1, x0, y1, incr, wDrawLineSolid, c, 0 );
+ wDrawLine( d, x0, y1, x0, y0, incr, wDrawLineSolid, c, 0 );
+ x0 += incr;
+ y0 += incr;
+ x1 -= incr;
+ y1 -= incr;
+ }
+}
+
+void winProc(
+ wWin_p win,
+ winProcEvent ev,
+ void * data )
+{
+ wPos_t w, h;
+ switch( ev ) {
+ case wResize_e:
+ wWinGetSize( win, &w, &h );
+ wDrawSetSize( *(wDraw_p*)data, w, h );
+ break;
+ default:
+ break;
+ }
+}
+
+
+wWin_p wMain( int argc, char * argv[] )
+{
+ mainW = wWinMainCreate( "colortst", 300, 300, NULL, "Main", "Main", 0, winProc, &mainD );
+ mainD = wDrawCreate( mainW, 0, 0, NULL, 0, 300, 300, NULL, redrawColor, NULL );
+ popupW = wWinPopupCreate( mainW, 300, 300, NULL, "Popup", "Popup", 0, winProc, &popupD );
+ popupD = wDrawCreate( popupW, 0, 0, NULL, 0, 300, 300, NULL, redrawGray, NULL );
+ wWinShow( popupW, TRUE );
+ /*font = wStandardFont( F_TIMES, 0, 0 );*/
+ return mainW;
+}
diff --git a/app/wlib/test/colortst.mak b/app/wlib/test/colortst.mak
new file mode 100644
index 0000000..8bfe5ac
--- /dev/null
+++ b/app/wlib/test/colortst.mak
@@ -0,0 +1,2 @@
+all:
+ nmake /f wtest.mak TEST=colortst
diff --git a/app/wlib/test/draw.c b/app/wlib/test/draw.c
new file mode 100644
index 0000000..795044a
--- /dev/null
+++ b/app/wlib/test/draw.c
@@ -0,0 +1,82 @@
+
+#include <stdio.h>
+#include "wlib.h"
+
+
+#define TRUE (1)
+#define FALSE (0)
+
+wFont_p font;
+wDraw_p draw1;
+wDrawColor black;
+static wPos_t origX, origY, oldX, oldY;
+
+void box( double x0, double y0, double x1, double y1, wDrawOpts opts )
+{
+ wDrawLine( draw1, x0, y0, x1, y0, 0, wDrawLineSolid,
+ black, opts );
+ wDrawLine( draw1, x1, y0, x1, y1, 0, wDrawLineSolid,
+ black, opts );
+ wDrawLine( draw1, x1, y1, x0, y1, 0, wDrawLineSolid,
+ black, opts );
+ wDrawLine( draw1, x0, y1, x0, y0, 0, wDrawLineSolid,
+ black, opts );
+}
+
+void doDraw( wAction_t action, wPos_t x, wPos_t y )
+{
+ char str[2];
+ switch (action & 0xFF) {
+ case wActionLDown:
+ origX = oldX = x;
+ origY = oldY = y;
+ box( origX, origY, oldX, oldY, wDrawOptTemp );
+ break;
+ case wActionLDrag:
+ box( origX, origY, oldX, oldY, wDrawOptTemp );
+ oldX = x; oldY = y;
+ box( origX, origY, oldX, oldY, wDrawOptTemp );
+ break;
+ case wActionLUp:
+ break;
+ case wActionText:
+ str[0] = (char)((action>>8)&0xFF);
+ str[1] = 0;
+ wDrawString( draw1, oldX, oldY, 0, str, font, 24, black, 0 );
+ break;
+ }
+}
+
+void doRedraw( wDraw_p bd, void * data, wPos_t x, wPos_t y )
+{
+ box( origX, origY, oldX, oldY, 0 );
+}
+
+void winProc(
+ wWin_p win,
+ winProcEvent ev,
+ void * data )
+{
+ wPos_t w, h;
+ switch( ev ) {
+ case wResize_e:
+ wWinGetSize( win, &w, &h );
+ wDrawSetSize( draw1, w, h );
+ break;
+ default:
+ break;
+ }
+}
+
+
+wWin_p wMain( int argc, char * argv[] )
+{
+
+ wWin_p mainW;
+
+ mainW = wWinMainCreate( "Fred", 2, 2, "Help", "Main", "Main", F_AUTOSIZE|F_MENUBAR, winProc, NULL );
+ font = wStandardFont( F_TIMES, FALSE, FALSE );
+ black = wDrawFindColor(0);
+ draw1 = wDrawCreate( mainW, 2, 2, NULL, 0, 300, 200, NULL, doRedraw, doDraw );
+ return mainW;
+}
diff --git a/app/wlib/test/draw.mak b/app/wlib/test/draw.mak
new file mode 100644
index 0000000..1f530e6
--- /dev/null
+++ b/app/wlib/test/draw.mak
@@ -0,0 +1,2 @@
+all:
+ nmake /f wtest.mak TEST=draw
diff --git a/app/wlib/test/dtest.bmp b/app/wlib/test/dtest.bmp
new file mode 100644
index 0000000..52bb88a
--- /dev/null
+++ b/app/wlib/test/dtest.bmp
@@ -0,0 +1,18 @@
+#define dtest_width 36
+#define dtest_height 36
+static char dtest_bits[] = {
+ 0xc0, 0xff, 0xff, 0xff, 0x0f, 0x20, 0x80, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0xff, 0xff, 0x0f, 0x08, 0x3c, 0x04, 0x80, 0x00, 0x04, 0x42, 0xf8, 0xff,
+ 0x0f, 0xc2, 0xff, 0x13, 0x00, 0x00, 0xc1, 0x00, 0x33, 0x00, 0x00, 0x41,
+ 0x81, 0x52, 0x00, 0x00, 0x41, 0x7e, 0x92, 0x00, 0x00, 0x41, 0x81, 0x22,
+ 0x01, 0x00, 0xc1, 0x00, 0x43, 0x02, 0x00, 0xc1, 0xff, 0x83, 0x04, 0x00,
+ 0x03, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x06, 0x12, 0x00, 0x09, 0x80,
+ 0x01, 0x24, 0x00, 0x91, 0x63, 0x00, 0x48, 0x00, 0x61, 0x1c, 0x00, 0x90,
+ 0x00, 0x21, 0x08, 0x00, 0x20, 0x01, 0xe1, 0xff, 0x0f, 0x40, 0x02, 0x21,
+ 0x08, 0x00, 0x80, 0x07, 0x41, 0x04, 0x00, 0x00, 0x08, 0x81, 0x1b, 0x00,
+ 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xd1, 0x07, 0xe0, 0x00, 0x08, 0x51, 0x85, 0x10, 0x01,
+ 0x08, 0x0a, 0x81, 0x10, 0x00, 0x08, 0x0a, 0x81, 0x10, 0x00, 0x08, 0x04,
+ 0x95, 0x14, 0x38, 0x0e, 0x0a, 0xad, 0x12, 0x44, 0x09, 0x0a, 0x85, 0x11,
+ 0x44, 0x09, 0x11, 0x85, 0x12, 0x65, 0x09, 0x12, 0x85, 0xe4, 0x58, 0x0e};
diff --git a/app/wlib/test/fred.bmp b/app/wlib/test/fred.bmp
new file mode 100644
index 0000000..11ac96d
--- /dev/null
+++ b/app/wlib/test/fred.bmp
@@ -0,0 +1,9 @@
+#define fred_width 24
+#define fred_height 24
+static char fred_bits[] = {
+ 0x3f, 0x1f, 0x00, 0x01, 0x21, 0x00, 0x01, 0x21, 0x00, 0x01, 0x21, 0x00,
+ 0x01, 0x21, 0x00, 0x01, 0x21, 0x00, 0x1f, 0x1f, 0x00, 0x01, 0x05, 0x00,
+ 0x01, 0x09, 0x00, 0x01, 0x09, 0x00, 0x01, 0x11, 0x00, 0x01, 0x11, 0x00,
+ 0x01, 0x21, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x02, 0x82, 0x00, 0x02, 0x82,
+ 0x00, 0x02, 0x82, 0x00, 0x3e, 0x82, 0x00, 0x02, 0x82, 0x00, 0x02, 0x82,
+ 0x00, 0x02, 0x82, 0x00, 0x02, 0x82, 0x00, 0x02, 0x82, 0x00, 0x7e, 0x7e};
diff --git a/app/wlib/test/fred.c b/app/wlib/test/fred.c
new file mode 100644
index 0000000..546d48c
--- /dev/null
+++ b/app/wlib/test/fred.c
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include "wlib.h"
+
+#include "fred.bmp"
+
+wMenu_p menu1a;
+wMenu_p menu2;
+wMenuList_p mlist1;
+wButton_p butt2;
+#define TRUE (1)
+#define FALSE (0)
+
+static void doButt1( void * data )
+{
+ static wBool_t busy2 = FALSE;
+ wControlActive( (wControl_p)butt2, busy2 );
+ busy2 = ! busy2;
+ wNotice( "doButt1", "Ok", NULL );
+
+}
+
+static void doButt2( void * data )
+{
+ wNotice( "doButt2", "Ok", NULL );
+}
+
+static long valInt1 = 4;
+static void doInt1( long val, void * data )
+{
+ wNotice( "doInt1", "Ok", NULL );
+}
+
+static double valFlt1 = 4;
+static void doFlt1( double val, void * data )
+{
+ wNotice( "doFlt1", "Ok", NULL );
+}
+
+static char valTxt1[80] = "abcdefghijkl";
+static void doTxt1( char * val, void * data )
+{
+ wNotice( "doText1", "Ok", NULL );
+}
+
+static long valList1 = 3;
+static void doList1( wIndex_t inx, char * name, wIndex_t op, void * data, void * itemContext )
+{
+ wNotice( name, "Ok", NULL );
+ wMenuListAdd( mlist1, 0, name, NULL );
+}
+
+static long valList2 = 4;
+static void doList2( wIndex_t inx, char * name, wIndex_t op, void * data, void * itemContext )
+{
+ wNotice( name, "Ok", NULL );
+ wMenuListDelete( mlist1, name );
+}
+
+static void doAnimal( void * data )
+
+{
+ wNotice( (char*)data, "Ok", NULL );
+}
+
+static long valList3 = 5;
+static void doList3( wIndex_t inx, char * name, wIndex_t op, void * data, void * itemContext )
+{
+ wNotice( name, "Ok", NULL );
+ wMenuPushCreate( menu1a, NULL, name, doAnimal, name );
+}
+
+static void doMList1( int index, char * name, void * data )
+{
+}
+
+void printNewPageSize( void )
+{
+}
+
+
+static wLines_t lines1[] = {
+ { 0, 100, 4, 200, 4 },
+ { 0, 200, 4, 100, 200 },
+ { 0, 100, 200, 200, 200 } };
+
+void populateList( wList_p l ) {
+ wListAddValue( l, "Aardvark", NULL, NULL );
+ wListAddValue( l, "Beaver", NULL, NULL );
+ wListAddValue( l, "Elephant", NULL, NULL );
+ wListAddValue( l, "Cow", NULL, NULL );
+ wListAddValue( l, "Donkey", NULL, NULL );
+ wListAddValue( l, "Jack Rabbit", NULL, NULL );
+ wListAddValue( l, "Fawn", NULL, NULL );
+ wListAddValue( l, "Nasty", NULL, NULL );
+ wListAddValue( l, "Giraffe", NULL, NULL );
+ wListAddValue( l, "Horse", NULL, NULL );
+ wListAddValue( l, "Igloo", NULL, NULL );
+ wListAddValue( l, "Lion", NULL, NULL );
+ wListAddValue( l, "Kangaroo", NULL, NULL );
+ wListAddValue( l, "Marmaset", NULL, NULL );
+}
+
+char * labels1[] = { "one", "two", "three", NULL };
+
+wWin_p wMain( int argc, char * argv[] )
+{
+
+ wWin_p mainW, popupW;
+ wList_p list1B;
+ wList_p list2B;
+ wList_p list3B;
+ wButtonBitMap_p fred_bmp;
+ wMenu_p menu1;
+ wMenu_p menu2a;
+ wDraw_p draw1;
+
+ mainW = wWinMainCreate( "Fred", 2, 2, "Help", "Main", F_AUTOSIZE|F_MENUBAR, NULL, NULL );
+ popupW = wWinPopupCreate( mainW, 200, 400, "Help2", "Popup", 0, NULL, NULL );
+
+ menu1 = wMenuBarAdd( mainW, "menu1", "&Menu1" );
+ wMenuPushCreate( menu1, "menu1-1", "&Dog", doAnimal, "Dog" );
+
+ wButtonCreate( mainW, 0, 0, "Button1", "Butt1", BB_DEFAULT, 0, doButt1, NULL );
+ fred_bmp = wButtonBitMapCreate( fred_width, fred_height, fred_bits );
+ butt2 = wButtonCreate( mainW, 100, 0, "Button2", (char*)fred_bmp, BO_ICON|BB_CANCEL, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ wButtonCreate( mainW, -1, 0, "Button2", (char*)fred_bmp, BO_ICON, 0, doButt2, NULL );
+ menu2 = wMenuCreate( mainW, 50, -1, "Menu2", "2" );
+ wMenuPushCreate( menu2, "menu2-1", "&Cat", doAnimal, "Cat" );
+ wMenuPushCreate( menu2, "menu2-2", "&Mouse", doAnimal, "Mouse" );
+ menu2a = wMenuMenuCreate( menu2, "menu2-3", "M&ore" );
+ wMenuPushCreate( menu2a, "menu2a-1", "&Wolf", doAnimal, "Wolf" );
+ wMenuPushCreate( menu2a, "menu2a-2", "&Pony", doAnimal, "Pony" );
+
+ menu1a = wMenuMenuCreate( menu1, "menu1-3", "M&ore" );
+ wMenuPushCreate( menu1a, "menu1a-1", "&Wolf", doAnimal, "Wolf" );
+ wMenuPushCreate( menu1a, "menu1a-2", "&Pony", doAnimal, "Pony" );
+ wMenuSeparatorCreate( menu1a );
+ mlist1 = wMenuListCreate( menu1a, "menu1-4", 10, doMList1 );
+ wMenuPushCreate( menu1a, "menu1-5", "&Zebra", doAnimal, "Zebra" );
+
+ wIntegerCreate( mainW, 50, -1, "Integer1", "Int1", 0, 50, -100, 100, &valInt1, doInt1, NULL );
+ wFloatCreate( mainW, 50, -1, "Float1", "Flt1", 0, 50, -100, 100, &valFlt1, doFlt1, NULL );
+ wStringCreate( mainW, 50, -1, "Text1", "Txt1", 0, 100, valTxt1, sizeof valTxt1, doTxt1, NULL );
+ wMessageCreate( mainW, 50, -1, "Message1", 150, "This is a message" );
+ wRadioCreate( mainW, 50, -4, NULL, NULL, 0, labels1, NULL, NULL, NULL );
+ wToggleCreate( mainW, 50, -4, NULL, NULL, 0, labels1, NULL, NULL, NULL );
+ wRadioCreate( mainW, 50, -4, NULL, NULL, BC_HORZ, labels1, NULL, NULL, NULL );
+ wToggleCreate( mainW, 50, -4, NULL, NULL, BC_HORZ, labels1, NULL, NULL, NULL );
+ wLineCreate( mainW, "Line1", sizeof lines1 / sizeof lines1[0], lines1 );
+
+ draw1 = wDrawCreate( mainW, 250, 50, "Draw-1", 0, 150, 150, NULL, NULL, NULL );
+ list1B = wListCreate( mainW, 250, -4, "List1", NULL, 0, 10, 200, &valList1, doList1, NULL );
+ populateList( list1B );
+ list2B = wDropListCreate( mainW, 250, -4, "List2", NULL, 0, 10, 200, &valList2, doList2, NULL );
+ populateList( list2B );
+ list3B = wComboListCreate( mainW, 250, -4, "List3", NULL, 0, 10, 200, &valList3, doList3, NULL );
+ populateList( list3B );
+
+
+ return mainW;
+}
diff --git a/app/wlib/test/fred.mak b/app/wlib/test/fred.mak
new file mode 100644
index 0000000..7fd2ede
--- /dev/null
+++ b/app/wlib/test/fred.mak
@@ -0,0 +1,2 @@
+all:
+ nmake /f wtest.mak TEST=fred
diff --git a/app/wlib/test/listtest.c b/app/wlib/test/listtest.c
new file mode 100644
index 0000000..6140fd6
--- /dev/null
+++ b/app/wlib/test/listtest.c
@@ -0,0 +1,96 @@
+#include <stdio.h>
+#include "wlib.h"
+
+
+#define TRUE (1)
+#define FALSE (0)
+
+wWin_p mainW, popup1W, popup2W;
+wList_p list1lB;
+wList_p list1dB;
+wList_p list1cB;
+wList_p list2lB;
+wList_p list2dB;
+wList_p list2cB;
+
+static long valList1 = 3;
+static void doList1( wIndex_t inx, char * name, wIndex_t op, void * data, void * itemContext )
+{
+ wNotice( name, "Ok", NULL );
+}
+
+static long valList2 = 4;
+static void doList2( wIndex_t inx, char * name, wIndex_t op, void * data, void * itemContext )
+{
+ wNotice( name, "Ok", NULL );
+}
+
+
+static long valList3 = 5;
+static void doList3( wIndex_t inx, char * name, wIndex_t op, void * data, void * itemContext )
+{
+ wNotice( name, "Ok", NULL );
+}
+
+
+void populateList( wList_p l ) {
+ wListAddValue( l, "Giraffe", NULL, NULL );
+ wListAddValue( l, "Marmaset", NULL, NULL );
+ wListAddValue( l, "Nasty", NULL, NULL );
+ wListAddValue( l, "Beaver", NULL, NULL );
+ wListAddValue( l, "Lion", NULL, NULL );
+ wListAddValue( l, "Donkey", NULL, NULL );
+ wListAddValue( l, "Elephant", NULL, NULL );
+ wListAddValue( l, "Jack Rabbit", NULL, NULL );
+ wListAddValue( l, "Horse", NULL, NULL );
+ wListAddValue( l, "Aardvark", NULL, NULL );
+ wListAddValue( l, "Igloo", NULL, NULL );
+ wListAddValue( l, "Cow", NULL, NULL );
+ wListAddValue( l, "Kangaroo", NULL, NULL );
+ wListAddValue( l, "Fawn", NULL, NULL );
+}
+
+wWin_p wMain( int argc, char * argv[] )
+{
+
+ wMenu_p m1, m2;
+
+ mainW = wWinMainCreate( "Fred", 40, 80, "Help", "Main", F_AUTOSIZE|F_MENUBAR, NULL, NULL );
+ popup1W = wWinPopupCreate( mainW, 2, 2, "Help2", "double click", F_AUTOSIZE|F_MENUBAR, NULL, NULL );
+
+ list1lB = wListCreate( popup1W, 2, 2, "List1", NULL, BL_DBLCLICK, 10, 200, &valList1, doList1, NULL );
+ populateList( list1lB );
+ list1dB = wDropListCreate( popup1W, 2, -4, "List2", NULL, BL_DBLCLICK, 10, 200, &valList2, doList2, NULL );
+ populateList( list1dB );
+ list1cB = wComboListCreate( popup1W, 2, -4, "List3", NULL, BL_DBLCLICK, 10, 200, &valList3, doList3, NULL );
+ populateList( list1cB );
+ m1 = wMenuBarAdd( popup1W, NULL, "Menu" );
+ wMenuPushCreate( m1, NULL, "Clear List 1", (wMenuCallBack_p)wListClear, list1lB );
+ wMenuPushCreate( m1, NULL, "Clear List 2", (wMenuCallBack_p)wListClear, list1dB );
+ wMenuPushCreate( m1, NULL, "Clear List 3", (wMenuCallBack_p)wListClear, list1cB );
+ wMenuPushCreate( m1, NULL, "Pop List 1", (wMenuCallBack_p)populateList, list1lB );
+ wMenuPushCreate( m1, NULL, "Pop List 2", (wMenuCallBack_p)populateList, list1dB );
+ wMenuPushCreate( m1, NULL, "Pop List 3", (wMenuCallBack_p)populateList, list1cB );
+
+
+ popup2W = wWinPopupCreate( mainW, 2, 2, "Help2", "single click", F_AUTOSIZE|F_MENUBAR, NULL, NULL );
+ list2lB = wListCreate( popup2W, 2, -4, "List1", NULL, BL_SORT, 10, 200, &valList1, doList1, NULL );
+ populateList( list2lB );
+ list2dB = wDropListCreate( popup2W, 2, -4, "List2", NULL, BL_SORT, 10, 200, &valList2, doList2, NULL );
+ populateList( list2dB );
+ list2cB = wComboListCreate( popup2W, 2, -4, "List3", NULL, BL_SORT, 10, 200, &valList3, doList3, NULL );
+ populateList( list2cB );
+ m2 = wMenuBarAdd( popup2W, NULL, "Menu" );
+ wMenuPushCreate( m2, NULL, "Clear List 1", (wMenuCallBack_p)wListClear, list2lB );
+ wMenuPushCreate( m2, NULL, "Clear List 2", (wMenuCallBack_p)wListClear, list2dB );
+ wMenuPushCreate( m2, NULL, "Clear List 3", (wMenuCallBack_p)wListClear, list2cB );
+ wMenuPushCreate( m2, NULL, "Pop List 1", (wMenuCallBack_p)populateList, list2lB );
+ wMenuPushCreate( m2, NULL, "Pop List 2", (wMenuCallBack_p)populateList, list2dB );
+ wMenuPushCreate( m2, NULL, "Pop List 3", (wMenuCallBack_p)populateList, list2cB );
+
+
+
+ wWinShow( popup1W, TRUE );
+ wWinShow( popup2W, TRUE );
+ return mainW;
+}
diff --git a/app/wlib/test/listtest.mak b/app/wlib/test/listtest.mak
new file mode 100644
index 0000000..3afe122
--- /dev/null
+++ b/app/wlib/test/listtest.mak
@@ -0,0 +1,2 @@
+all:
+ nmake /f wtest.mak TEST=listtest
diff --git a/app/wlib/test/splash.rc b/app/wlib/test/splash.rc
new file mode 100644
index 0000000..5fb8a8c
--- /dev/null
+++ b/app/wlib/test/splash.rc
@@ -0,0 +1,17 @@
+#define IDD_DLG1 1000
+#define IDC_IMG1 1001
+#define IDC_STC1 1002
+#define IDC_STC2 1003
+#define IDC_IMG2 1004
+#define IDI_LOGO 1000
+IDD_DLG1 DIALOGEX 6,6,194,102
+CAPTION "IDD_DLG"
+FONT 8,"MS Sans Serif",0,0
+STYLE 0x10CF0000
+BEGIN
+ CONTROL "",IDC_IMG1,"Static",0x50000203,196,99,92,26
+ CONTROL "Testapplication",IDC_STC1,"Static",0x50000201,0,57,194,9
+ CONTROL "Application is starting",IDC_STC2,"Static",0x50000000,-2,68,199,9
+ CONTROL "",IDC_IMG2,"Static",0x50000203,0,0,226,57
+END
+IDI_LOGO IMAGE DISCARDABLE "logo.bmp"
diff --git a/app/wlib/test/test.vcproj b/app/wlib/test/test.vcproj
new file mode 100644
index 0000000..f857ec8
--- /dev/null
+++ b/app/wlib/test/test.vcproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="test"
+ ProjectGUID="{B500EFE5-B60C-4CB5-B818-52ACF4B3C30A}"
+ RootNamespace="test"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(InputDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\include"
+ PreprocessorDefinitions="WIN32;WINVER=0x0500;_DEBUG;_WINDOWS;WINDOWS;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="htmlhelp.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="htmlhelp.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="false"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\testapp.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/app/wlib/test/testapp.c b/app/wlib/test/testapp.c
new file mode 100644
index 0000000..6342801
--- /dev/null
+++ b/app/wlib/test/testapp.c
@@ -0,0 +1,125 @@
+/** \file testapp.c
+ * Small test application to demonstrate functionality of the XTrkCad windowing library wlib
+ *
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/test/testapp.c,v 1.2 2007-09-14 16:17:24 m_fischer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C)
+ *
+ * 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 <stdio.h>
+#include "wlib.h"
+
+#define APPNAME "TESTAPP"
+#define WINDOWTITLE "Test Application"
+
+#define TRUE (1)
+#define FALSE (0)
+
+/**
+ * doFile: callback funtion for file submenu
+ */
+
+void doFile( void * cmd )
+{
+ switch ((int)cmd) {
+ case 1:
+ break;
+ case 0: /* 'Quit ' */
+ wExit( 0 ); /* terminate application */
+ }
+}
+
+
+wWin_p wMain( int argc, char * argv[] )
+{
+
+ wWin_p mainW;
+ wMenu_p menu1;
+ wMenu_p menu2;
+ int i;
+ char buffer[ 80 ];
+
+ /* add a splash window */
+ wCreateSplash( WINDOWTITLE, /* name of application to show */
+ "1.0" /* application version information */
+ );
+
+ wFlush(); /* make sure splash window is shown */
+
+ /* create main window */
+ mainW = wWinMainCreate( APPNAME, /* application name */
+ 200, /* position x */
+ 100, /* position y */
+ "Help", /* help topic */
+ WINDOWTITLE, /* window title */
+ APPNAME, /* window name */
+ F_RESIZE|F_MENUBAR, /* options */
+ NULL, /* window callback function */
+ NULL /* pointer to user data */
+ );
+
+ wWinShow( mainW, FALSE );
+
+ /* add a submenu */
+ menu1 = wMenuBarAdd( mainW, /* parent window */
+ NULL, /* help topic */
+ "File" /* submenu title */
+ );
+
+ /* create a menuitem in submenu */
+ wMenuPushCreate( menu1, /* parent menu */
+ NULL, /* help topic */
+ "Test", /* submenu title */
+ 0, /* accelerator key */
+ doFile, /* callback funtion */
+ (void*)1 /* pointer to user data */
+ );
+
+
+ /* create a separator before 'Quit' */
+ wMenuSeparatorCreate( menu1 );
+
+ /* create a menuitem in submenu */
+ wMenuPushCreate( menu1, /* parent menu */
+ NULL, /* help topic */
+ "Quit", /* submenu title */
+ 0, /* accelerator key */
+ doFile, /* callback funtion */
+ (void*)0 /* pointer to user data */
+ );
+
+ /* create a second submenu */
+ menu2 = wMenuBarAdd( mainW, /* parent window */
+ NULL, /* help topic */
+ "Help" /* submenu title */
+ );
+
+ for( i = 5; i > 0; i-- ) {
+ sprintf(buffer, "Countdown %d", i );
+ wSetSplashInfo( buffer );
+ wPause( 1000L );
+ }
+
+ wWinShow( mainW, TRUE );
+ wPause ( 2000L );
+ wDestroySplash(); /* remove the splash window again */
+
+ return mainW;
+}
diff --git a/app/wlib/test/wtest.def b/app/wlib/test/wtest.def
new file mode 100644
index 0000000..e8a631f
--- /dev/null
+++ b/app/wlib/test/wtest.def
@@ -0,0 +1,9 @@
+NAME Generic
+DESCRIPTION 'wtest'
+EXETYPE WINDOWS
+STUB 'WINSTUB.EXE'
+CODE MOVEABLE DISCARDABLE
+DATA MOVEABLE MULTIPLE
+HEAPSIZE 1024
+STACKSIZE 5120
+EXPORTS MainWndProc @1 About @2 \ No newline at end of file
diff --git a/app/wlib/test/wtest.ico b/app/wlib/test/wtest.ico
new file mode 100644
index 0000000..998d604
--- /dev/null
+++ b/app/wlib/test/wtest.ico
Binary files differ
diff --git a/app/wlib/test/wtest.mak b/app/wlib/test/wtest.mak
new file mode 100644
index 0000000..6c1a62a
--- /dev/null
+++ b/app/wlib/test/wtest.mak
@@ -0,0 +1,23 @@
+all: $(TEST).exe wtest.res
+
+some: wtest.exe wtest.res
+
+FREDOBJS = $(TEST).obj
+
+.c.obj:
+ @cl /nologo /DWINDOWS /c /I../include /Od /Zp /W3 $<
+
+mswlibl:
+ echo making mswlib.lib
+ cd ..\mswlib
+ makemsw
+ cd ..\wtest
+
+$(TEST).exe: $(FREDOBJS) wtest.def
+ @echo /nologo > $(TEST).lnk
+ @echo $(TEST).obj >> $(TEST).lnk
+ @echo $(TEST) >> $(TEST).lnk
+ @echo $(TEST) >> $(TEST).lnk
+ @echo ..\mswlib\Debug\wlib.lib >> $(TEST).lnk
+ link @$(TEST).lnk
+ rc /I.. /I..\mswlib wtest.rc $(TEST).exe \ No newline at end of file
diff --git a/app/wlib/test/wtest.rc b/app/wlib/test/wtest.rc
new file mode 100644
index 0000000..13d6d46
--- /dev/null
+++ b/app/wlib/test/wtest.rc
@@ -0,0 +1,22 @@
+#include <windows.h>
+#include "w.h"
+#include "mswlib.h"
+MSWAPPICON ICON wtest.ico
+Generic MENU
+BEGIN
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "About Generic...", IDM_ABOUT
+ END
+END
+
+AboutBox DIALOG 22, 17, 144, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About Generic"
+BEGIN
+ CTEXT "WLIB Windows", -1, 0, 5, 144, 8
+ CTEXT "Test Application", -1, 0, 14, 144, 8
+ CTEXT "Version 0.1", -1, 0, 34, 144, 8
+ DEFPUSHBUTTON "OK" IDOK, 53, 59, 32, 14, WS_GROUP
+END
+#include "mswlib.rc"