diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2016-12-28 16:52:56 +0100 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2016-12-28 16:52:56 +0100 |
commit | 7b358424ebad9349421acd533c2fa1cbf6cf3e3e (patch) | |
tree | 686678532eefed525c242fd214d0cfb2914726c5 /app/wlib |
Initial import of xtrkcad version 1:4.0.2-2
Diffstat (limited to 'app/wlib')
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 = >k_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 = ¬iceW; + + 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 ×Font[bold][italic]; + else if (family == F_HELV) + return &helvFont[bold][italic]; + else + return NULL; +} + +void wSelectFont( const char * title ) +{ + doChooseFont(); +} + + +wFontSize_t wSelectedFontSize( void ) +{ + return fontSize; +} + +void wSetSelectedFontSize(int size) +{ + fontSize = (wFontSize_t)size; +} + +/* + ***************************************************************************** + * + * Misc + * + ***************************************************************************** + */ + + + +void wDrawFilledRectangle( + wDraw_p d, + wPos_t px, + wPos_t py, + wPos_t sx, + wPos_t sy, + wDrawColor color, + wDrawOpts opts ) +{ + RECT rect; + if (d == NULL) + return; + setDrawBrush( d->hDc, d, color, opts ); + rect.left = XINCH2PIX(d,px); + rect.right = XINCH2PIX(d,px+sx); + rect.top = YINCH2PIX(d,py+sy); + rect.bottom = YINCH2PIX(d,py); + if ( rect.right < 0 || + rect.bottom < 0 ) + return; + if ( rect.left < 0 ) + rect.left = 0; + if ( rect.top < 0 ) + rect.top = 0; + if ( rect.left > d->w || + rect.top > d->h ) + return; + if ( rect.right > d->w ) + rect.right = d->w; + if ( rect.bottom > d->h ) + rect.bottom = d->h; + Rectangle( d->hDc, rect.left, rect.top, rect.right, rect.bottom ); + if (d->hWnd) { + rect.top--; + rect.left--; + rect.bottom++; + rect.right++; + myInvalidateRect( d, &rect ); + } +} + +#ifdef DRAWFILLPOLYLOG +static FILE * logF; +#endif +static int wFillPointsMax = 0; +static POINT * wFillPoints; + +static void addPoint( + int * pk, + POINT * pp, + RECT * pr ) +{ +#ifdef DRAWFILLPOLYLOG +fprintf( logF, " q[%d] = {%d,%d}\n", *pk, pp->x, pp->y ); +#endif + if ( *pk > 0 && + wFillPoints[(*pk)-1].x == pp->x && wFillPoints[(*pk)-1].y == pp->y ) + return; + wFillPoints[ (*pk)++ ] = *pp; + if (pp->x<pr->left) + pr->left = pp->x; + if (pp->x>pr->right) + pr->right = pp->x; + if (pp->y<pr->top) + pr->top = pp->y; + if (pp->y>pr->bottom) + pr->bottom = pp->y; +} + +void wDrawFilledPolygon( + wDraw_p d, + wPos_t p[][2], + int cnt, + wDrawColor color, + wDrawOpts opts ) +{ + RECT rect; + int i, k; + POINT p0, p1, q0, q1; + static POINT zero = { 0, 0 }; + wBool_t p1Clipped; + + if (d == NULL) + return; + if (cnt*2 > wFillPointsMax) { + wFillPoints = realloc( wFillPoints, cnt * 2 * sizeof *(POINT*)NULL ); + wFillPointsMax = cnt*2; + } + setDrawBrush( d->hDc, d, color, opts ); + p1.x = rect.left = rect.right = XINCH2PIX(d,p[cnt-1][0]-1); + p1.y = rect.top = rect.bottom = YINCH2PIX(d,p[cnt-1][1]+1); +#ifdef DRAWFILLPOLYLOG +logF = fopen( "log.txt", "a" ); +fprintf( logF, "\np[%d] = {%d,%d}\n", cnt-1, p1.x, p1.y ); +#endif + p1Clipped = FALSE; + for ( i=k=0; i<cnt; i++ ) { + p0 = p1; + p1.x = XINCH2PIX(d,p[i][0]-1); + p1.y = YINCH2PIX(d,p[i][1]+1); +#ifdef DRAWFILLPOLYLOG +fprintf( logF, "p[%d] = {%d,%d}\n", i, p1.x, p1.y ); +#endif + q0 = p0; + q1 = p1; + if ( clip0( &q0, &q1, NULL ) ) { +#ifdef DRAWFILLPOLYLOG +fprintf( logF, " clip( {%d,%d} {%d,%d} ) = {%d,%d} {%d,%d}\n", p0.x, p0.y, p1.x, p1.y, q0.x, q0.y, q1.x, q1.y ); +#endif + if ( q0.x != p0.x || q0.y != p0.y ) { + if ( k > 0 && ( q0.x > q0.y ) != ( wFillPoints[k-1].x > wFillPoints[k-1].y ) ) + addPoint( &k, &zero, &rect ); + addPoint( &k, &q0, &rect ); + } + addPoint( &k, &q1, &rect ); + p1Clipped = ( q1.x != p1.x || q1.y != p1.y ); + } + } + if ( p1Clipped && + ( wFillPoints[k-1].x > wFillPoints[k-1].y ) != ( wFillPoints[0].x > wFillPoints[0].y ) ) + addPoint( &k, &zero, &rect ); +#ifdef DRAWFILLPOLYLOG +fflush( logF ); +fclose( logF ); +#endif + if ( k <= 2 ) + return; + Polygon( d->hDc, wFillPoints, k ); + if (d->hWnd) { + rect.top--; + rect.left--; + rect.bottom++; + rect.right++; + myInvalidateRect( d, &rect ); + } +} + +#define MAX_FILLCIRCLE_POINTS (30) +void wDrawFilledCircle( + wDraw_p d, + wPos_t x, + wPos_t y, + wPos_t r, + wDrawColor color, + wDrawOpts opts ) +{ + POINT p0, p1; + RECT rect; + static wPos_t circlePts[MAX_FILLCIRCLE_POINTS][2]; + int inx, cnt; + double dang; + + p0.x = XINCH2PIX(d,x-r); + p0.y = YINCH2PIX(d,y+r)+1; + p1.x = XINCH2PIX(d,x+r); + p1.y = YINCH2PIX(d,y-r)+1; + + setDrawBrush( d->hDc, d, color, opts ); + if ( noNegDrawArgs > 0 && ( p0.x < 0 || p0.y < 0 ) ) { + if ( r > MAX_FILLCIRCLE_POINTS ) + cnt = MAX_FILLCIRCLE_POINTS; + else if ( r > 8 ) + cnt = r; + else + cnt = 8; + dang = 360.0/cnt; + for ( inx=0; inx<cnt; inx++ ) { + circlePts[inx][0] = x + (int)(r * mswcos( inx*dang ) + 0.5 ); + circlePts[inx][1] = y + (int)(r * mswsin( inx*dang ) + 0.5 ); + } + wDrawFilledPolygon( d, circlePts, cnt, color, opts ); + } else { + Ellipse( d->hDc, p0.x, p0.y, p1.x, p1.y ); + if (d->hWnd) { + rect.top = p0.y; + rect.bottom = p1.y; + rect.left = p0.x; + rect.right = p1.x; + myInvalidateRect( d, &rect ); + } + } +} + +/* + ***************************************************************************** + * + * Misc + * + ***************************************************************************** + */ + + +void wDrawSaveImage( + wDraw_p bd ) +{ + if ( bd->hBmBackup ) { + SelectObject( bd->hDcBackup, bd->hBmBackupOld ); + DeleteObject( bd->hBmBackup ); + bd->hBmBackup = (HBITMAP)0; + } + if ( bd->hDcBackup == (HDC)0 ) + bd->hDcBackup = CreateCompatibleDC( bd->hDc ); + bd->hBmBackup = CreateCompatibleBitmap( bd->hDc, bd->w, bd->h ); + bd->hBmBackupOld = SelectObject( bd->hDcBackup, bd->hBmBackup ); + BitBlt( bd->hDcBackup, 0, 0, bd->w, bd->h, bd->hDc, 0, 0, SRCCOPY ); +} + +void wDrawRestoreImage( + wDraw_p bd ) +{ + if ( bd->hBmBackup == (HBITMAP)0 ) { + mswFail( "wDrawRestoreImage: hBmBackup == 0" ); + return; + } + BitBlt( bd->hDc, 0, 0, bd->w, bd->h, bd->hDcBackup, 0, 0, SRCCOPY ); + InvalidateRect( bd->hWnd, NULL, FALSE ); +} + + +void wDrawClear( wDraw_p d ) +{ + RECT rect; + SetROP2( d->hDc, R2_WHITE ); + Rectangle( d->hDc, 0, 0, d->w, d->h ); + if (d->hWnd) { + rect.top = 0; + rect.bottom = d->h; + rect.left = 0; + rect.right = d->w; + InvalidateRect( d->hWnd, &rect, FALSE ); + } +} + + +void wDrawSetSize( + wDraw_p d, + wPos_t width, + wPos_t height ) +{ + d->w = width; + d->h = height; + if (!SetWindowPos( d->hWnd, HWND_TOP, 0, 0, + d->w, d->h, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("wDrawSetSize: SetWindowPos"); + } + /*wRedraw( d );*/ +} + + +void wDrawGetSize( + wDraw_p d, + wPos_t * width, + wPos_t * height ) +{ + *width = d->w-2; + *height = d->h-2; +} + + +void * wDrawGetContext( wDraw_p d ) +{ + return d->data; +} + + +double wDrawGetDPI( wDraw_p d ) +{ + return d->DPI; +} + +double wDrawGetMaxRadius( wDraw_p d ) +{ + return 4096.0; +} + +void wDrawClip( + wDraw_p d, + wPos_t x, + wPos_t y, + wPos_t w, + wPos_t h ) +{ + int ix0, iy0, ix1, iy1; + HRGN hRgnClip; + ix0 = XINCH2PIX(d,x); + iy0 = YINCH2PIX(d,y); + ix1 = XINCH2PIX(d,x+w); + iy1 = YINCH2PIX(d,y+h); + /* Note: Ydim is upside down so iy1<iy0 */ + hRgnClip = CreateRectRgn( ix0, iy1, ix1, iy0 ); + SelectClipRgn( d->hDc, hRgnClip ); + DeleteObject( hRgnClip ); +} + + +void wRedraw( wDraw_p d ) +{ + wDrawClear( d ); + if (d->drawRepaint) + d->drawRepaint( d, d->data, 0, 0 ); +} + +/* + ***************************************************************************** + * + * BitMap + * + ***************************************************************************** + */ + +struct wDrawBitMap_t { + wDrawBitMap_p next; + wPos_t x; + wPos_t y; + wPos_t w; + wPos_t h; + char * bmx; + wDrawColor color; + HBITMAP bm; + }; +wDrawBitMap_p bmRoot = NULL; + + +void wDrawBitMap( + wDraw_p d, + wDrawBitMap_p bm, + wPos_t px, + wPos_t py, + wDrawColor dc, + wDrawOpts dopt ) +{ + HDC bmDc, hDc; + HBITMAP oldBm; + DWORD mode; + int x0, y0; + RECT rect; + + x0 = XINCH2PIX(d,px-bm->x); + y0 = YINCH2PIX(d,py-bm->y+bm->h); +#ifdef LATER + if ( noNegDrawArgs > 0 && ( x0 < 0 || y0 < 0 ) ) + return; +#endif + if (dopt & wDrawOptTemp) { + mode = tmpOp; + } else if (dc == wDrawColorWhite) { + mode = clrOp; + dc = wDrawColorBlack; + } else { + mode = setOp; + } + + if ( bm->color != dc ) { + if ( bm->bm ) + DeleteObject( bm->bm ); + bm->bm = mswCreateBitMap( mswGetColor(d->hasPalette,dc) /*colorPalette.palPalEntry[dc]*/, RGB( 255, 255, 255 ), + RGB( 255, 255, 255 ), bm->w, bm->h, bm->bmx ); + bm->color = dc; + } + if ( (dopt & wDrawOptNoClip) != 0 && + ( px < 0 || px >= d->w || py < 0 || py >= d->h ) ) { + x0 += d->x; + y0 += d->y; + hDc = GetDC( ((wControl_p)(d->parent))->hWnd ); + bmDc = CreateCompatibleDC( hDc ); + oldBm = SelectObject( bmDc, bm->bm ); + BitBlt( hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, tmpOp ); + SelectObject( bmDc, oldBm ); + DeleteDC( bmDc ); + ReleaseDC( ((wControl_p)(d->parent))->hWnd, hDc ); + return; + } + + bmDc = CreateCompatibleDC( d->hDc ); + setDrawMode( d->hDc, d, 0, wDrawLineSolid, dc, dopt ); + oldBm = SelectObject( bmDc, bm->bm ); + BitBlt( d->hDc, x0, y0, bm->w, bm->h, bmDc, 0, 0, mode ); + SelectObject( bmDc, oldBm ); + DeleteDC( bmDc ); + if (d->hWnd) { + rect.top = y0-1; + rect.bottom = rect.top+bm->h+1; + rect.left = x0-1; + rect.right = rect.left+bm->w+1; + myInvalidateRect( d, &rect ); + } +} + + +wDrawBitMap_p wDrawBitMapCreate( + wDraw_p d, + int w, + int h, + int x, + int y, + const char * bits ) +{ + wDrawBitMap_p bm; + int bmSize = ((w+7)/8) * h; + bm = (wDrawBitMap_p)malloc( sizeof *bm ); + if (bmRoot == NULL) { + bmRoot = bm; + bm->next = NULL; + } else { + bm->next = bmRoot; + bmRoot = bm; + } + bm->x = x; + bm->y = y; + bm->w = w; + bm->h = h; + bm->bmx = malloc( bmSize ); + bm->bm = (HBITMAP)0; + bm->color = -1; + memcpy( bm->bmx, bits, bmSize ); + /*bm->bm = mswCreateBitMap( GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), w, h, bits );*/ + return bm; +} + +/* + ***************************************************************************** + * + * Create + * + ***************************************************************************** + */ + +int doSetFocus = 1; + +long FAR PASCAL XEXPORT mswDrawPush( + HWND hWnd, + UINT message, + UINT wParam, + LONG lParam ) +{ +#ifdef WIN32 + long inx = GetWindowLong( hWnd, GWL_ID ); +#else + short inx = GetWindowWord( hWnd, GWW_ID ); +#endif + wDraw_p b; + short int ix, iy; + wPos_t x, y; + HDC hDc; + PAINTSTRUCT ps; + wAction_t action; + RECT rect; + HWND activeWnd; + HWND focusWnd; + wAccelKey_e extChar; + + switch( message ) { + case WM_CREATE: + b = (wDraw_p)mswMapIndex( inx ); + hDc = GetDC(hWnd); + if ( b->option & BD_DIRECT ) { + b->hDc = hDc; + b->hBm = 0; + b->hBmOld = 0; + } else { + b->hDc = CreateCompatibleDC( hDc ); + b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); + b->hBmOld = SelectObject( b->hDc, b->hBm ); + } + if (mswPalette) { + SelectPalette( b->hDc, mswPalette, 0 ); + RealizePalette( b->hDc ); + } + b->wFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSX ); + b->hFactor = (double)GetDeviceCaps( b->hDc, LOGPIXELSY ); + b->DPI = 96.0; /*min( b->wFactor, b->hFactor );*/ + b->hWnd = hWnd; + SetROP2( b->hDc, R2_WHITE ); + Rectangle( b->hDc, 0, 0, b->w, b->h ); + if ( (b->option & BD_DIRECT) == 0 ) { + SetROP2( hDc, R2_WHITE ); + Rectangle( hDc, 0, 0, b->w, b->h ); + ReleaseDC( hWnd, hDc ); + } + break; + case WM_SIZE: + b = (wDraw_p)mswMapIndex( inx ); + ix = LOWORD( lParam ); + iy = HIWORD( lParam ); + b->w = ix+2; + b->h = iy+2; + if (b->hWnd) { + if ( b->option & BD_DIRECT ) { + } else { + hDc = GetDC( b->hWnd ); + b->hBm = CreateCompatibleBitmap( hDc, b->w, b->h ); + DeleteObject(SelectObject( b->hDc, b->hBm )); + ReleaseDC( b->hWnd, hDc ); + SetROP2( b->hDc, R2_WHITE ); + Rectangle( b->hDc, 0, 0, b->w, b->h ); + } + } + /*if (b->drawResize) + b->drawResize( b, b->size );*/ + if (b->drawRepaint) + b->drawRepaint( b, b->data, 0, 0 ); + return 0; + case WM_MOUSEMOVE: + activeWnd = GetActiveWindow(); + focusWnd = GetFocus(); + if (focusWnd != hWnd) { + b = (wDraw_p)mswMapIndex( inx ); + if (!b) + break; + if ( !((wControl_p)b->parent) ) + break; + if ( ((wControl_p)b->parent)->hWnd != activeWnd ) + break; + } + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + if (message == WM_LBUTTONDOWN) + action = wActionLDown; + else if (message == WM_RBUTTONDOWN) + action = wActionRDown; + else if (message == WM_LBUTTONUP) + action = wActionLUp; + else if (message == WM_RBUTTONUP) + action = wActionRUp; + else { + if ( (wParam & MK_LBUTTON) != 0) + action = wActionLDrag; + else if ( (wParam & MK_RBUTTON) != 0) + action = wActionRDrag; + else + action = wActionMove; + } + b = (wDraw_p)mswMapIndex( inx ); + if (!b) + break; + if (doSetFocus && message != WM_MOUSEMOVE) + SetFocus( ((wControl_p)b->parent)->hWnd ); + if ( (b->option&BD_NOCAPTURE) == 0 ) { + if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN) + SetCapture( b->hWnd ); + else if (message == WM_LBUTTONUP || message == WM_RBUTTONUP) + ReleaseCapture(); + } + ix = LOWORD( lParam ); + iy = HIWORD( lParam ); + x = XPIX2INCH( b, ix ); + y = YPIX2INCH( b, iy ); + if (b->action) + b->action( b, b->data, action, x, y ); + if (b->hWnd) + UpdateWindow(b->hWnd); + return 0; + case WM_CHAR: + b = (wDraw_p)mswMapIndex( inx ); + extChar = wAccelKey_None; + if (lParam & 0x01000000L) + switch( wParam ) { + case VK_DELETE: extChar = wAccelKey_Del; break; + case VK_INSERT: extChar = wAccelKey_Ins; break; + case VK_HOME: extChar = wAccelKey_Home; break; + case VK_END: extChar = wAccelKey_End; break; + case VK_PRIOR: extChar = wAccelKey_Pgup; break; + case VK_NEXT: extChar = wAccelKey_Pgdn; break; + case VK_UP: extChar = wAccelKey_Up; break; + case VK_DOWN: extChar = wAccelKey_Down; break; + case VK_RIGHT: extChar = wAccelKey_Right; break; + case VK_LEFT: extChar = wAccelKey_Left; break; + case VK_BACK: extChar = wAccelKey_Back; break; + /*case VK_F1: extChar = wAccelKey_F1; break;*/ + case VK_F2: extChar = wAccelKey_F2; break; + case VK_F3: extChar = wAccelKey_F3; break; + case VK_F4: extChar = wAccelKey_F4; break; + case VK_F5: extChar = wAccelKey_F5; break; + case VK_F6: extChar = wAccelKey_F6; break; + case VK_F7: extChar = wAccelKey_F7; break; + case VK_F8: extChar = wAccelKey_F8; break; + case VK_F9: extChar = wAccelKey_F9; break; + case VK_F10: extChar = wAccelKey_F10; break; + case VK_F11: extChar = wAccelKey_F11; break; + case VK_F12: extChar = wAccelKey_F12; break; + } + if (b && b->action) { + if (extChar != wAccelKey_None) + b->action( b, b->data, wActionExtKey + ( (int)extChar << 8 ), 0, 0 ); + else + b->action( b, b->data, wActionText + ( wParam << 8 ), 0, 0 ); + } + return 0; + + case WM_PAINT: + b = (wDraw_p)mswMapIndex( inx ); + if (b && b->type == B_DRAW) { + if (GetUpdateRect( b->hWnd, &rect, FALSE )) { + hDc = BeginPaint( hWnd, &ps ); + if ( b->hasPalette ) { + int winPaletteClock = mswGetPaletteClock(); + if ( b->paletteClock < winPaletteClock ) { + RealizePalette( hDc ); + b->paletteClock = winPaletteClock; + } + } + BitBlt( hDc, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, + b->hDc, rect.left, rect.top, + SRCCOPY ); + EndPaint( hWnd, &ps ); + } + } + break; + case WM_DESTROY: + b = (wDraw_p)mswMapIndex( inx ); + if (b && b->type == B_DRAW) { + if (b->hDc) { + DeleteDC( b->hDc ); + b->hDc = (HDC)0; + } + if (b->hDcBackup) { + DeleteDC( b->hDcBackup ); + b->hDcBackup = (HDC)0; + } + } + break; + default: + break; + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static LRESULT drawMsgProc( wDraw_p b, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + wAction_t action; + + switch( message ) { + case WM_MOUSEWHEEL: + /* handle mouse wheel events */ + /* fwKeys = GET_KEYSTATE_WPARAM(wParam); modifier keys are currently ignored */ + if ( GET_WHEEL_DELTA_WPARAM(wParam) > 0 ) { + action = wActionWheelUp; + } else { + action = wActionWheelDown; + } + if (b->action) + b->action( b, b->data, action, 0, 0 ); + return 0; + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static void drawDoneProc( wControl_p b ) +{ + wDraw_p d = (wDraw_p)b; + if (d->hBm) { + SelectObject( d->hDc, d->hBmOld ); + DeleteObject( d->hBm ); + d->hBm = (HBITMAP)0; + } + if (d->hPen) { + SelectObject( d->hDc, GetStockObject( BLACK_PEN ) ); + DeleteObject( d->hPen ); + d->hPen = (HPEN)0; + } + if (d->hBrush) { + SelectObject( d->hDc, GetStockObject( BLACK_BRUSH) ); + DeleteObject( d->hBrush ); + d->hBrush = (HBRUSH)0; + } + if (d->hDc) { + DeleteDC( d->hDc ); + d->hDc = (HDC)0; + } + if ( d->hDcBackup ) { + DeleteDC( d->hDcBackup ); + d->hDcBackup = (HDC)0; + } + while (bmRoot) { + if (bmRoot->bm) + DeleteObject( bmRoot->bm ); + bmRoot = bmRoot->next; + } +} + + +static callBacks_t drawCallBacks = { + NULL, + drawDoneProc, + (messageCallback_p)drawMsgProc }; + +wDraw_p drawList = NULL; + + +void mswRedrawAll( void ) +{ + wDraw_p p; + for ( p=drawList; p; p=p->drawNext ) { + if (p->drawRepaint) + p->drawRepaint( p, p->data, 0, 0 ); + } +} + + +void mswRepaintAll( void ) +{ + wDraw_p b; + HDC hDc; + RECT rect; + PAINTSTRUCT ps; + + for ( b=drawList; b; b=b->drawNext ) { + if (GetUpdateRect( b->hWnd, &rect, FALSE )) { + hDc = BeginPaint( b->hWnd, &ps ); + BitBlt( hDc, rect.left, rect.top, + rect.right-rect.left, rect.bottom-rect.top, + b->hDc, rect.left, rect.top, + SRCCOPY ); + EndPaint( b->hWnd, &ps ); + } + } +} + + +wDraw_p wDrawCreate( + wWin_p parent, + wPos_t x, + wPos_t y, + const char * helpStr, + long option, + wPos_t w, + wPos_t h, + void * data, + wDrawRedrawCallBack_p redrawProc, + wDrawActionCallBack_p action ) +{ + wDraw_p d; + RECT rect; + int index; + HDC hDc; + + if ( noNegDrawArgs < 0 ) { + wPrefGetInteger( "msw tweak", "NoNegDrawArgs", &noNegDrawArgs, 0 ); + wPrefGetInteger( "msw tweak", "NoFlatEndCaps", &noFlatEndCaps, 0 ); + } + + d = mswAlloc( parent, B_DRAW, NULL, sizeof *d, data, &index ); + mswComputePos( (wControl_p)d, x, y ); + d->w = w; + d->h = h; + d->drawRepaint = NULL; + d->action = action; + d->option = option; + + d->hWnd = CreateWindow( mswDrawWindowClassName, NULL, + WS_CHILDWINDOW|WS_VISIBLE|WS_BORDER, + d->x, d->y, w, h, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + + if (d->hWnd == (HWND)0) { + mswFail( "CreateWindow(DRAW)" ); + return d; + } + + GetWindowRect( d->hWnd, &rect ); + + d->w = rect.right - rect.left; + d->h = rect.bottom - rect.top; + d->drawRepaint = redrawProc; + /*if (d->drawRepaint) + d->drawRepaint( d, d->data, 0.0, 0.0 );*/ + + mswAddButton( (wControl_p)d, FALSE, helpStr ); + mswCallBacks[B_DRAW] = &drawCallBacks; + d->drawNext = drawList; + drawList = d; + if (mswPalette) { + hDc = GetDC( d->hWnd ); + d->hasPalette = TRUE; + SelectPalette( hDc, mswPalette, 0 ); + ReleaseDC( d->hWnd, hDc ); + } + return d; +} + +/* + ***************************************************************************** + * + * Bitmaps + * + ***************************************************************************** + */ + +wDraw_p wBitMapCreate( wPos_t w, wPos_t h, int planes ) +{ + wDraw_p d; + HDC hDc; + + d = (wDraw_p)calloc(1,sizeof *d); + d->type = B_DRAW; + d->shown = TRUE; + d->x = 0; + d->y = 0; + d->w = w; + d->h = h; + d->drawRepaint = NULL; + d->action = NULL; + d->option = 0; + + hDc = GetDC(mswHWnd); + d->hDc = CreateCompatibleDC( hDc ); + if ( d->hDc == (HDC)0 ) { + wNoticeEx( NT_ERROR, "CreateBitMap: CreateDC fails", "Ok", NULL ); + return FALSE; + } + d->hBm = CreateCompatibleBitmap( hDc, d->w, d->h ); + if ( d->hBm == (HBITMAP)0 ) { + wNoticeEx( NT_ERROR, "CreateBitMap: CreateBM fails", "Ok", NULL ); + return FALSE; + } + d->hasPalette = (GetDeviceCaps(hDc,RASTERCAPS ) & RC_PALETTE) != 0; + ReleaseDC( mswHWnd, hDc ); + d->hBmOld = SelectObject( d->hDc, d->hBm ); + if (mswPalette) { + SelectPalette( d->hDc, mswPalette, 0 ); + RealizePalette( d->hDc ); + } + d->wFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSX ); + d->hFactor = (double)GetDeviceCaps( d->hDc, LOGPIXELSY ); + d->DPI = 96.0; /*min( d->wFactor, d->hFactor );*/ + d->hWnd = 0; + SetROP2( d->hDc, R2_WHITE ); + Rectangle( d->hDc, 0, 0, d->w, d->h ); + return d; +} + +wBool_t wBitMapDelete( wDraw_p d ) +{ + if (d->hPen) { + SelectObject( d->hDc, GetStockObject( BLACK_PEN ) ); + DeleteObject( d->hPen ); + d->hPen = (HPEN)0; + } + if (d->hBm) { + SelectObject( d->hDc, d->hBmOld ); + DeleteObject( d->hBm ); + d->hBm = (HBITMAP)0; + } + if (d->hDc) { + DeleteDC( d->hDc ); + d->hDc = (HDC)0; + } + free(d); + return TRUE; +} + +wBool_t wBitMapWriteFile( wDraw_p d, const char * fileName ) +{ + char *pixels; + int j, ww, chunk; + FILE * f; + BITMAPFILEHEADER bmfh; + struct { + BITMAPINFOHEADER bmih; + RGBQUAD colors[256]; + } bmi; + int rc; + + if ( d->hBm == 0) + return FALSE; + f = wFileOpen( fileName, "wb" ); + if (!f) { + wNoticeEx( NT_ERROR, fileName, "Ok", NULL ); + return FALSE; + } + ww = ((d->w +3) / 4) * 4; + bmfh.bfType = 'B'+('M'<<8); + bmfh.bfSize = (long)(sizeof bmfh) + (long)(sizeof bmi.bmih) + (long)(sizeof bmi.colors) + (long)ww * (long)(d->h); + bmfh.bfReserved1 = 0; + bmfh.bfReserved2 = 0; + bmfh.bfOffBits = sizeof bmfh + sizeof bmi.bmih + sizeof bmi.colors; + fwrite( &bmfh, 1, sizeof bmfh, f ); + bmi.bmih.biSize = sizeof bmi.bmih; + bmi.bmih.biWidth = d->w; + bmi.bmih.biHeight = d->h; + bmi.bmih.biPlanes = 1; + bmi.bmih.biBitCount = 8; + bmi.bmih.biCompression = BI_RGB; + bmi.bmih.biSizeImage = 0; + bmi.bmih.biXPelsPerMeter = 75*(10000/254); + bmi.bmih.biYPelsPerMeter = 75*(10000/254); + bmi.bmih.biClrUsed = bmi.bmih.biClrImportant = mswGetColorList( bmi.colors ); + SelectObject( d->hDc, d->hBmOld ); + rc = GetDIBits( d->hDc, d->hBm, 0, 1, NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS ); + if ( rc == 0 ) { + wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bitmapinfo from Bitmap", "Ok", NULL ); + return FALSE; + } + bmi.bmih.biClrUsed = 256; + fwrite( &bmi.bmih, 1, sizeof bmi.bmih, f ); + fwrite( bmi.colors, 1, sizeof bmi.colors, f ); + chunk = 32000/ww; + pixels = (char*)malloc( ww*chunk ); + if ( pixels == NULL ) { + wNoticeEx( NT_ERROR, "WriteBitMap: no memory", "OK", NULL ); + return FALSE; + } + for (j=0;j<d->h;j+=chunk) { + if (j+chunk>d->h) + chunk = d->h-j; + rc = GetDIBits( d->hDc, d->hBm, j, chunk, pixels, (BITMAPINFO*)&bmi, DIB_RGB_COLORS ); + if ( rc == 0 ) + if ( rc == 0 ) { + wNoticeEx( NT_ERROR, "WriteBitMap: Can't get bits from Bitmap", "Ok", NULL ); + return FALSE; + } + rc = fwrite( pixels, 1, ww*chunk, f ); + if (rc != ww*chunk) { + wNoticeEx( NT_ERROR, "WriteBitMap: Bad fwrite", "Ok", NULL); + } + } + free( pixels ); + SelectObject( d->hDc, d->hBm ); + fclose( f ); + return TRUE; +} + diff --git a/app/wlib/mswlib/mswedit.c b/app/wlib/mswlib/mswedit.c new file mode 100644 index 0000000..5bb26ec --- /dev/null +++ b/app/wlib/mswlib/mswedit.c @@ -0,0 +1,726 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <stdio.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + + +struct wString_t { + WOBJ_COMMON + char * valueP; + wIndex_t valueL; + wStringCallBack_p action; + }; + +struct wInteger_t { + WOBJ_COMMON + long low, high; + long * valueP; + long oldValue; + wIntegerCallBack_p action; + }; + +struct wFloat_t { + WOBJ_COMMON + double low, high; + double * valueP; + double oldValue; + wFloatCallBack_p action; + }; + + +static XWNDPROC oldEditProc = NULL; +static XWNDPROC newEditProc; +static void triggerString( wControl_p b ); +#ifdef LATER +static void triggerInteger( wControl_p b ); +static void triggerFloat( wControl_p b ); +#endif + + +long FAR PASCAL _export pushEdit( + HWND hWnd, + UINT message, + UINT wParam, + LONG lParam ) +{ + /* Catch <Return> and cause focus to leave control */ +#ifdef WIN32 + long inx = GetWindowLong( hWnd, GWL_ID ); +#else + short inx = GetWindowWord( hWnd, GWW_ID ); +#endif + wControl_p b = mswMapIndex( inx ); + + switch (message) { + case WM_CHAR: + if ( b != NULL) { + switch( wParam ) { + case 0x0D: + case 0x1B: + case 0x09: + SetFocus( ((wControl_p)(b->parent))->hWnd ); + SendMessage( ((wControl_p)(b->parent))->hWnd, WM_CHAR, + wParam, lParam ); + /*SendMessage( ((wControl_p)(b->parent))->hWnd, WM_COMMAND, + inx, MAKELONG( hWnd, EN_KILLFOCUS ) );*/ + return 0L; + } + } + break; + + case WM_KEYUP: + if ( b != NULL) + switch (b->type) { + case B_STRING: + if (((wString_p)b)->action) + mswSetTrigger( (wControl_p)b, triggerString ); + break; +#ifdef LATER + case B_INTEGER: + if (((wInteger_p)b)->action) + mswSetTrigger( (wControl_p)b, triggerInteger ); + break; + case B_FLOAT: + if (((wFloat_p)b)->action) + mswSetTrigger( (wControl_p)b, triggerFloat ); + break; +#endif + } + break; + + } + return CallWindowProc( oldEditProc, hWnd, message, wParam, lParam ); +} + +/* + ***************************************************************************** + * + * String Boxes + * + ***************************************************************************** + */ + + +void wStringSetValue( + wString_p b, + const char * arg ) +{ + WORD len = strlen( arg ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)arg ); +#ifdef WIN32 + SendMessage( b->hWnd, EM_SETSEL, len, len ); + SendMessage( b->hWnd, EM_SCROLLCARET, 0, 0L ); +#else + SendMessage( b->hWnd, EM_SETSEL, 0, MAKELPARAM(len,len) ); +#endif + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); +} + + +void wStringSetWidth( + wString_p b, + wPos_t w ) +{ + int rc; + b->w = w; + rc = SetWindowPos( b->hWnd, HWND_TOP, 0, 0, + b->w, b->h, SWP_NOMOVE|SWP_NOZORDER ); +} + + +const char * wStringGetValue( + wString_p b ) +{ + static char buff[256]; + SendMessage( b->hWnd, WM_GETTEXT, sizeof buff, (DWORD)buff ); + return buff; +} + + +static void triggerString( + wControl_p b ) +{ + wString_p bs = (wString_p)b; + int cnt; + + if (bs->action) { + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bs->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (bs->valueP) + strcpy( bs->valueP, mswTmpBuff ); + bs->action( mswTmpBuff, bs->data ); + mswSetTrigger( NULL, NULL ); + } +} + + +LRESULT stringProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wString_p bs = (wString_p)b; + int cnt; + int modified; + + switch( message ) { + + case WM_COMMAND: + switch (WCMD_PARAM_NOTF) { + case EN_KILLFOCUS: + modified = (int)SendMessage( bs->hWnd, (UINT)EM_GETMODIFY, 0, 0L ); + if (!modified) + break; + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bs->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (bs->valueP) + strncpy( bs->valueP, mswTmpBuff, bs->valueL ); + if (bs->action) { + bs->action( mswTmpBuff, bs->data ); + mswSetTrigger( NULL, NULL ); + } + break; + SendMessage( bs->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L ); + } + break; + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static callBacks_t stringCallBacks = { + mswRepaintLabel, + NULL, + stringProc }; + + +wString_p wStringCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + char *valueP, + wIndex_t valueL, + wStringCallBack_p action, + void *data ) +{ + wString_p b; + RECT rect; + int index; + DWORD style = 0; + + b = (wString_p)mswAlloc( parent, B_STRING, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->valueP = valueP; + b->valueL = valueL; + b->labelY += 2; + b->action = action; + if (option & BO_READONLY) + style |= ES_READONLY; + +#ifdef WIN32 + b->hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); +#else + b->hWnd = CreateWindow( "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); +#endif + if (b->hWnd == NULL) { + mswFail("CreateWindow(STRING)"); + return b; + } + +#ifdef CONTROL3D + Ctl3dSubclassCtl( b->hWnd); +#endif + + newEditProc = MakeProcInstance( (XWNDPROC)pushEdit, mswHInst ); + oldEditProc = (XWNDPROC)GetWindowLong(b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newEditProc ); + + if (b->valueP) { + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)b->valueP ); + } + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[B_STRING] = &stringCallBacks; + mswChainFocus( (wControl_p)b ); + return b; +} +#ifdef LATER + +/* + ***************************************************************************** + * + * Integer Value Boxes + * + ***************************************************************************** + */ + + +#define MININT ((long)0x80000000) +#define MAXINT ((long)0x7FFFFFFF) + + +void wIntegerSetValue( + wInteger_p b, + long arg ) +{ + b->oldValue = arg; + wsprintf( mswTmpBuff, "%ld", arg ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); +} + + +long wIntegerGetValue( + wInteger_p b ) +{ + return b->oldValue; +} + + +static void triggerInteger( + wControl_p b ) +{ + wInteger_p bi = (wInteger_p)b; + int cnt; + long value; + char * cp; + + if (bi->action) { + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bi->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0 ) + return; + value = strtol( mswTmpBuff, &cp, 10 ); + if (*cp != '\0' || value < bi->low || value > bi->high ) + return; + if (bi->oldValue == value) + return; + if (bi->valueP) + *bi->valueP = value; + bi->oldValue = value; + bi->action( value, bi->data ); + } +} + + +LRESULT integerProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wInteger_p bi = (wInteger_p)b; + int inx; + int cnt; + long value; + char * cp; + wBool_t ok; + int modified; + + switch( message ) { + + case WM_COMMAND: + switch (WCMD_PARAM_NOTF) { + case EN_KILLFOCUS: + ok = TRUE; + modified = (int)SendMessage( bi->hWnd, (UINT)EM_GETMODIFY, 0, 0L ); + if (!modified) + break; + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bi->hWnd, (UINT)EM_GETLINE, 0, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0 && 0 >= bi->low && 0 <= bi->high ) { + value = 0; + } else { + value = strtol( mswTmpBuff, &cp, 10 ); + if (*cp != '\0' || value < bi->low || value > bi->high ) { + inx = GetWindowWord( bi->hWnd, GWW_ID ); + if (wWinIsVisible(bi->parent)) { + PostMessage( ((wControl_p)(bi->parent))->hWnd, + WM_NOTVALID, inx, 0L ); + return TRUE; + } else { + if (value < bi->low) + value = bi->low; + else + value = bi->high; + sprintf( mswTmpBuff, "%ld", value ); + SendMessage( bi->hWnd, (UINT)WM_SETTEXT, 0, + (DWORD)(LPSTR)mswTmpBuff ); + } + } + } + bi->oldValue = value; + if (bi->valueP) + *bi->valueP = value; + if (bi->action) { + bi->action( value, bi->data ); + mswSetTrigger( NULL, NULL ); + } + SendMessage( bi->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L ); + } + break; + + case WM_NOTVALID: + wsprintf( mswTmpBuff, "Please enter a value between %ld and %ld", + bi->low, bi->high ); + if (bi->low > MININT && bi->high < MAXINT) + sprintf( mswTmpBuff, + "Please enter an integer value between %ld and %ld", + bi->low, bi->high ); + else if (bi->low > MININT) + sprintf( mswTmpBuff, + "Please enter an integer value greater or equal to %ld", + bi->low ); + else if (bi->high < MAXINT) + sprintf( mswTmpBuff, + "Please enter an integer value less or equal to %ld", + bi->high ); + else + strcpy( mswTmpBuff, "Please enter an integer value" ); + MessageBox( bi->hWnd, mswTmpBuff, "Invalid entry", MB_OK ); + SetFocus( bi->hWnd ); +#ifdef WIN32 + SendMessage( bi->hWnd, EM_SETSEL, 0, 0x7fff ); + SendMessage( bi->hWnd, EM_SCROLLCARET, 0, 0L ); +#else + SendMessage( bi->hWnd, EM_SETSEL, 0, MAKELONG(0,0x7fff) ); +#endif + return TRUE; + + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static callBacks_t integerCallBacks = { + mswRepaintLabel, + NULL, + integerProc }; + + +wInteger_p wIntegerCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + long low, + long high, + long *valueP, + wIntegerCallBack_p action, + void *data ) +{ + wInteger_p b; + RECT rect; + int index; + DWORD style = 0; + + b = mswAlloc( parent, B_INTEGER, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->low = low; + b->high = high; + b->valueP = valueP; + b->labelY += 2; + b->action = action; + if (option & BO_READONLY) + style |= ES_READONLY; + + b->hWnd = CreateWindow( "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(INTEGER)"); + return b; + } + +#ifdef CONTROL3D + Ctl3dSubclassCtl( b->hWnd); +#endif + + newEditProc = MakeProcInstance( (XWNDPROC)pushEdit, mswHInst ); + oldEditProc = (XWNDPROC)GetWindowLong(b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newEditProc ); + + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + if (b->valueP) { + wsprintf( mswTmpBuff, "%ld", *b->valueP ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + b->oldValue = *b->valueP; + } else + b->oldValue = 0; + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[ B_INTEGER ] = &integerCallBacks; + mswChainFocus( (wControl_p)b ); + return b; +} + +/* + ***************************************************************************** + * + * Floating Point Value Boxes + * + ***************************************************************************** + */ + + +#define MINFLT (-1000000) +#define MAXFLT (1000000) + + + +void wFloatSetValue( + wFloat_p b, + double arg ) +{ + b->oldValue = arg; + sprintf( mswTmpBuff, "%0.3f", arg ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); +} + + +double wFloatGetValue( + wFloat_p b ) +{ + return b->oldValue; +} + + +static void triggerFloat( + wControl_p b ) +{ + wFloat_p bf = (wFloat_p)b; + int cnt; + double value; + char * cp; + + if (bf->action) { + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bf->hWnd, (UINT)EM_GETLINE, 0, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0) + return; + value = strtod( mswTmpBuff, &cp ); + if (*cp != '\0' || value < bf->low || value > bf->high ) + return; + if (bf->oldValue == value) + return; + bf->oldValue = value; + if (bf->valueP) + *bf->valueP = value; + bf->action( wFloatGetValue(bf), bf->data ); + } +} + + +LRESULT floatProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wFloat_p bf = (wFloat_p)b; + int inx; + int cnt; + double value; + char * cp; + wBool_t ok; + int modified; + + switch( message ) { + + case WM_COMMAND: + switch (HIWORD(lParam)) { + case EN_KILLFOCUS: + ok = TRUE; + modified = (int)SendMessage( bf->hWnd, (UINT)EM_GETMODIFY, 0, 0L ); + if (!modified) + break; + *(WPARAM*)&mswTmpBuff[0] = 78; + cnt = (int)SendMessage( bf->hWnd, (UINT)EM_GETLINE, 0, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (strcmp( mswTmpBuff, "-" )==0 && 0 >= bf->low && 0 <= bf->high ) { + value = 0; + } else { + value = strtod( mswTmpBuff, &cp ); + if (*cp != '\0' || value < bf->low || value > bf->high ) { + inx = GetWindowWord( bf->hWnd, GWW_ID ); + if (wWinIsVisible(bf->parent)) { + PostMessage( ((wControl_p)(bf->parent))->hWnd, + WM_NOTVALID, inx, 0L ); + return TRUE; + } else { + if (value < bf->low) + value = bf->low; + else + value = bf->high; + sprintf( mswTmpBuff, "%0.3f", value ); + SendMessage( bf->hWnd, (UINT)WM_SETTEXT, 0, + (DWORD)(LPSTR)mswTmpBuff ); + } + } + } + bf->oldValue = value; + if (bf->valueP) + *bf->valueP = value; + if (bf->action) { + bf->action( value, bf->data ); + mswSetTrigger( NULL, NULL ); + } + SendMessage( bf->hWnd, (UINT)EM_SETMODIFY, FALSE, 0L ); + } + break; + + case WM_NOTVALID: + if (bf->low > MINFLT && bf->high < MAXFLT) + sprintf( mswTmpBuff, + "Please enter an float value between %0.3f and %0.3f", + bf->low, bf->high ); + else if (bf->low > MINFLT) + sprintf( mswTmpBuff, + "Please enter an float value greater or equal to %0.3f", + bf->low ); + else if (bf->high < MAXFLT) + sprintf( mswTmpBuff, + "Please enter an float value less or equal to %0.3f", + bf->high ); + else + strcpy( mswTmpBuff, "Please enter an float value" ); + MessageBox( bf->hWnd, mswTmpBuff, "Invalid entry", MB_OK ); + SetFocus( bf->hWnd ); +#ifdef WIN32 + SendMessage( bi->hWnd, EM_SETSEL, 0, 0x7fff ); + SendMessage( bi->hWnd, EM_SCROLLCARET, 0, 0L ); +#else + SendMessage( bi->hWnd, EM_SETSEL, 0, MAKELONG(0,0x7fff) ); +#endif + return TRUE; + + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + + +static callBacks_t floatCallBacks = { + mswRepaintLabel, + NULL, + floatProc }; + + +wFloat_p wFloatCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + double low, + double high, + double *valueP, + wFloatCallBack_p action, + void *data ) +{ + wFloat_p b; + RECT rect; + int index; + DWORD style = 0; + + b = mswAlloc( parent, B_FLOAT, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->low = low; + b->high = high; + b->valueP = valueP; + b->labelY += 2; + b->action = action; + if (option & BO_READONLY) + style |= ES_READONLY; + + b->hWnd = CreateWindow( "EDIT", NULL, + ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | style, + b->x, b->y, + width, mswEditHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(FLOAT)"); + return b; + } + +#ifdef CONTROL3D + Ctl3dSubclassCtl( b->hWnd); +#endif + + newEditProc = MakeProcInstance( (XWNDPROC)pushEdit, mswHInst ); + oldEditProc = (XWNDPROC)GetWindowLong(b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newEditProc ); + + if (b->valueP) { + b->oldValue = *b->valueP; + } else + b->oldValue = 0.0; + if (b->valueP) + sprintf( mswTmpBuff, "%0.3f", *b->valueP ); + else + strcpy( mswTmpBuff, "0.000" ); + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + SendMessage( b->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)mswTmpBuff ); + SendMessage( b->hWnd, EM_SETMODIFY, FALSE, 0L ); + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[ B_FLOAT ] = &floatCallBacks; + mswChainFocus( (wControl_p)b ); + return b; +} +#endif diff --git a/app/wlib/mswlib/mswint.h b/app/wlib/mswlib/mswint.h new file mode 100644 index 0000000..2311415 --- /dev/null +++ b/app/wlib/mswlib/mswint.h @@ -0,0 +1,193 @@ +#include "wlib.h" +#include "mswlib.h" +#include "dynarr.h" +#ifndef WIN32 +/*#define CONTROL3D*/ +#endif +#include "stdio.h" + +#ifdef CONTROL3D +#include "ctl3d.h" +#endif + +#ifdef WIN32 +#ifdef FAR +#undef FAR +#endif +#define FAR +#define _export +#define MoveTo(HDC,X,Y) MoveToEx(HDC,X,Y,NULL) +#define READ (0) +#define WRITE (1) +#define XEXPORT +#define XWNDPROC WNDPROC +#define WCMD_PARAM_HWND lParam +#define WCMD_PARAM_NOTF HIWORD(wParam) +#define WCMD_PARAM_ID LOWORD(wParam) +#define WSCROLL_PARAM_CODE LOWORD(wParam) +#define WSCROLL_PARAM_NPOS HIWORD(wParam) +#define WSCROLL_PARAM_HWND lParam +#else +#define XEXPORT _export +#define XWNDPROC FARPROC +#define WCMD_PARAM_HWND LOWORD(lParam) +#define WCMD_PARAM_NOTF HIWORD(lParam) +#define WCMD_PARAM_ID wParam +#define WSCROLL_PARAM_CODE wParam +#define WSCROLL_PARAM_NPOS LOWORD(lParam) +#define WSCROLL_PARAM_HWND HIWORD(lParam) +#endif + +#define CAST_AWAY_CONST (char *) + +#define BOOL_T wBool_t +#define POS_T wPos_t +#define INDEX_T wIndex_t +#define INTEGER_T wInteger_t + +typedef enum { + W_MAIN, W_POPUP, + B_BUTTON, B_STRING, B_INTEGER, B_FLOAT, + B_LIST, B_DROPLIST, B_COMBOLIST, + B_RADIO, B_TOGGLE, + B_DRAW, B_TEXT, B_MESSAGE, B_LINES, + B_MENUITEM, B_CHOICEITEM, B_BOX, + B_BITMAP } wType_e; + +typedef void (*repaintProcCallback_p)( HWND, wControl_p ); +typedef void (*doneProcCallback_p)( wControl_p b ); +typedef LRESULT (*messageCallback_p)( wControl_p, HWND, UINT, WPARAM, LPARAM ); +typedef void (*setTriggerCallback_p)( wControl_p b ); +typedef void (*setBusyCallback_p)( wControl_p, BOOL_T ); +typedef void (*showCallback_p)( wControl_p, BOOL_T ); +typedef void (*setPosCallback_p)( wControl_p, wPos_t, wPos_t ); + +typedef struct { + repaintProcCallback_p repaintProc; + doneProcCallback_p doneProc; + messageCallback_p messageProc; + setBusyCallback_p setBusyProc; + showCallback_p showProc; + setPosCallback_p setPosProc; + } callBacks_t; + +#define CALLBACK_CNT (B_BOX+1) +extern callBacks_t *mswCallBacks[CALLBACK_CNT]; + + +#define WOBJ_COMMON \ + wType_e type; \ + wControl_p next; \ + wControl_p synonym; \ + wWin_p parent; \ + POS_T x, y; \ + POS_T w, h; \ + long option; \ + POS_T labelX, labelY; \ + const char * labelStr; \ + const char * helpStr; \ + const char * tipStr; \ + HWND hWnd; \ + void * data;\ + wControl_p focusChainNext; \ + wBool_t shown; + +struct wControl_t { + WOBJ_COMMON + }; + +typedef struct { + unsigned key; + wDrawColor color; + } wIconColorMap_t; +#define mswIcon_bitmap (1) +#define mswIcon_pixmap (2) + +struct wIcon_t { + int type; + wPos_t w; /**< width */ + wPos_t h; /**< height */ + wDrawColor color; + int colorcnt; /**< number of colors */ + RGBQUAD *colormap; + char *pixels; /**< pointer to pixel information */ + int transparent; /**< index of transparent color */ + }; + +struct wDraw_t { + WOBJ_COMMON + HDC hDc; + double wFactor; + double hFactor; + double DPI; + wDrawRedrawCallBack_p drawRepaint; + wDrawActionCallBack_p action; + HBITMAP hBm; + HPEN hPen; + HBRUSH hBrush; + wDraw_p drawNext; + HBITMAP hBmOld; + wBool_t hasPalette; + int paletteClock; + HBITMAP hBmBackup; + HDC hDcBackup; + HBITMAP hBmBackupOld; + }; + +extern HINSTANCE mswHInst; +extern char mswTmpBuff[1024]; +extern HWND mswHWnd; +extern const char *mswDrawWindowClassName; +char *mswProfileFile; +extern int mswEditHeight; +extern int mswAllowBalloonHelp; +extern HFONT mswOldTextFont; +extern HFONT mswLabelFont; +extern wDrawColor wDrawColorWhite; +extern wDrawColor wDrawColorBlack; +extern long mswThickFont; +extern double mswScale; + +DWORD mswGetBaseStyle( wWin_p ); +char * mswStrdup( const char * ); +HBITMAP mswCreateBitMap( COLORREF, COLORREF, COLORREF, int, int, const char * ); +void mswFail( const char * ); +void mswResize( wWin_p ); +wControl_p mswMapIndex( INDEX_T ); +void mswButtPush( wControl_p ); +void * mswAlloc( wWin_p, wType_e, const char *, int, void *, int * ); +void mswComputePos( wControl_p, wPos_t, wPos_t ); +void mswAddButton( wControl_p, BOOL_T, const char * ); +void mswRepaintLabel( HWND, wControl_p ); +int mswRegister( wControl_p ); +void mswUnregister( int ); +void mswChainFocus( wControl_p ); +void mswSetFocus( wControl_p ); +void mswSetTrigger( wControl_p, setTriggerCallback_p ); +void mswMenuPush( wControl_p ); +void mswCreateCheckBitmaps( void ); +long FAR PASCAL XEXPORT mswDrawPush( HWND, UINT, UINT, LONG ); +#ifdef WIN32 +DWORD GetTextExtent( HDC, CHAR *, UINT ); +#endif +void mswRedrawAll( void ); +void mswRepaintAll( void ); +HDC mswGetPrinterDC( void ); +int mswMenuAccelerator( wWin_p, long ); +void mswMenuMove( wMenu_p, wPos_t, wPos_t ); +void mswRegisterBitMap( HBITMAP ); +void mswFontInit( void ); +void mswInitColorPalette( void ); +void mswPutCustomColors( void ); +COLORREF mswGetColor( wBool_t, wDrawColor ); +int mswGetColorList( RGBQUAD * ); +int mswGetPaletteClock( void ); +HPALETTE mswPalette; +HPALETTE mswCreatePalette( void ); + +/* mswbitmaps.c */ +void deleteBitmaps( void ); +void mswDrawIcon( HDC, int, int, wIcon_p, int, COLORREF, COLORREF ); + +/* gwin32.c*/ +char *g_win32_getlocale (void);
\ No newline at end of file diff --git a/app/wlib/mswlib/mswlines.c b/app/wlib/mswlib/mswlines.c new file mode 100644 index 0000000..be1330d --- /dev/null +++ b/app/wlib/mswlib/mswlines.c @@ -0,0 +1,98 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Lines + * + ***************************************************************************** + */ + +struct wLine_t { + WOBJ_COMMON + int count; + wLines_t * lines; + }; + +static void repaintLines( HWND hWnd, wControl_p b ) +{ + int lastWidth; + HDC hDc; + wLine_p bl = (wLine_p)(b); + wLines_p lp; + HPEN oldPen, newPen; + + lastWidth = -1; + hDc = GetDC( hWnd ); + for (lp=bl->lines; lp<&bl->lines[bl->count]; lp++) { + if (lastWidth != lp->width) { + lastWidth = lp->width; + newPen = CreatePen( PS_SOLID, lastWidth, RGB(0,0,0) ); + oldPen = SelectObject( hDc, newPen ); + DeleteObject( oldPen ); + } + MoveTo( hDc, lp->x0, lp->y0 ); + LineTo( hDc, lp->x1, lp->y1 ); + } + ReleaseDC( hWnd, hDc ); +} + + +static callBacks_t linesCallBacks = { + repaintLines, + NULL, + NULL }; + + +wLine_p wLineCreate( + wWin_p parent, + const char * labelStr, + int count, + wLines_t * lines ) +{ + wLine_p b; + wLines_p lp; + POS_T minX, maxX, minY, maxY; + int index; + + if (count <= 0) + return NULL; + b = (wLine_p)mswAlloc( parent, B_LINES, labelStr, sizeof *b, NULL, &index ); + b->count = count; + b->lines = lines; + + lp = lines; + minX = maxX = lp->x0; + minY = maxY = lp->y0; + for (lp=lines; lp<&b->lines[count]; lp++) { + if (minX > lp->x0) + minX = lp->x0; + if (maxX < lp->x0) + maxX = lp->x0; + if (minY > lp->y0) + minY = lp->y0; + if (maxY < lp->y0) + maxY = lp->y0; + if (minX > lp->x1) + minX = lp->x1; + if (maxX < lp->x1) + maxX = lp->x1; + if (minY > lp->y1) + minY = lp->y1; + if (maxY < lp->y1) + maxY = lp->y1; + } + b->x = minX; + b->y = minY; + b->w = maxX-minX; + b->h = maxY-minY; + mswAddButton( (wControl_p)b, FALSE, NULL ); + mswCallBacks[B_LINES] = &linesCallBacks; + return b; +} diff --git a/app/wlib/mswlib/mswlist.c b/app/wlib/mswlib/mswlist.c new file mode 100644 index 0000000..968624a --- /dev/null +++ b/app/wlib/mswlib/mswlist.c @@ -0,0 +1,1173 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * List Boxes + * + ***************************************************************************** + */ + +static XWNDPROC oldListProc = NULL; +static XWNDPROC newListProc; +static XWNDPROC oldComboProc = NULL; +static XWNDPROC newComboProc; + +struct wList_t { + WOBJ_COMMON + int count; + int last; + long * valueP; + wListCallBack_p action; + wBool_t editable; + int colCnt; + wPos_t * colWidths; + wBool_t * colRightJust; + const char * * colTitles; + wPos_t maxWidth; + wPos_t scrollPos; + HWND hScrollWnd; + wPos_t scrollH; + wPos_t dragPos; + int dragCol; + wPos_t dragColWidth; + }; + + +typedef struct { + void * itemContext; + wIcon_p bm; + wBool_t selected; + } listData; + +static int LIST_HEIGHT = 19; +static int listTitleHeight = 16; + + +void wListClear( + wList_p b ) +{ + UINT msg; + if (b->type==B_LIST) + msg = LB_RESETCONTENT; + else + msg = CB_RESETCONTENT; + SendMessage( b->hWnd, msg, 0, 0 ); + b->last = -1; + b->count = 0; +} + + + +void wListSetSize( wList_p bl, wPos_t w, wPos_t h ) +{ + int rc; + RECT rect; + wPos_t y; + + bl->w = w; + bl->h = h; + y = bl->y; + if ( bl->hScrollWnd && bl->maxWidth > bl->w ) + h -= bl->scrollH; + if ( bl->colTitles ) { + h -= listTitleHeight; + y += listTitleHeight; + } + rc = SetWindowPos( bl->hWnd, HWND_TOP, 0, 0, + w, h, SWP_NOMOVE|SWP_NOZORDER); + if ( bl->hScrollWnd ) { + if ( bl->maxWidth > bl->w ) { + GetClientRect( bl->hWnd, &rect ); + rc = SetWindowPos( bl->hScrollWnd, HWND_TOP, bl->x, y+rect.bottom+2, + bl->w, bl->scrollH, SWP_NOZORDER); + ShowWindow( bl->hScrollWnd, SW_SHOW ); + } else { + ShowWindow( bl->hScrollWnd, SW_HIDE ); + } + } + +} + + +void wListSetIndex( + wList_p bl, + int index ) +{ + listData * ldp; + + wListGetCount(bl); + if ( index >= bl->count ) + index = bl->count-1; + if ( bl->last == index && index == -1 ) + return; + if ( bl->type==B_LIST && (bl->option&BL_MANY) != 0 ) { + if ( bl->last != -1 ) + SendMessage( bl->hWnd, LB_SETSEL, 0, MAKELPARAM(bl->last,0) ); + if ( index >= 0 ) + SendMessage( bl->hWnd, LB_SETSEL, 1, MAKELPARAM(index, 0) ); + } else { + SendMessage( bl->hWnd, + bl->type==B_LIST?LB_SETCURSEL:CB_SETCURSEL, index, 0 ); + } + if ( bl->last >= 0 ) { + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + bl->last, 0L ); + if ( ldp && ldp!=(void*)LB_ERR ) + ldp->selected = FALSE; + } + if ( index >= 0 ) { + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + index, 0L ); + if ( ldp && ldp!=(void*)LB_ERR ) + ldp->selected = TRUE; + } + /*if (b->option&BL_ICON)*/ + InvalidateRect( bl->hWnd, NULL, FALSE ); + bl->last = index; +} + + +wIndex_t wListGetIndex( + wList_p b ) +{ + return b->last; +} + + +void wListSetActive( + wList_p b, + int inx, + wBool_t active ) +{ +} + + +void wListSetEditable( + wList_p b, + wBool_t editable ) +{ + b->editable = editable; +} + + +void wListSetValue( + wList_p bl, + const char * val ) +{ + if ( bl->type == B_DROPLIST ) { + SendMessage( bl->hWnd, WM_SETTEXT, 0, (DWORD)(LPSTR)val ); + bl->last = -1; + } +} + + +wIndex_t wListFindValue( + wList_p bl, + const char * val ) +{ + wIndex_t inx; + WORD cnt; + wListGetCount(bl); + for ( inx = 0; inx < bl->count ; inx++ ) { + cnt = (int)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETTEXT:CB_GETLBTEXT), inx, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if ( strcmp( val, mswTmpBuff ) == 0 ) + return inx; + } + return -1; +} + + +wIndex_t wListGetValues( + wList_p bl, + char * s, + int siz, + void * * listContextRef, + void * * itemContextRef ) +{ + WORD cnt; + WORD msg; + WORD inx = bl->last; + listData *ldp = NULL; + if ( bl->type==B_DROPLIST && bl->last < 0 ) { + msg = WM_GETTEXT; + inx = sizeof mswTmpBuff; + } else { + if ( bl->last < 0 ) + goto EMPTY; + if ( bl->type==B_LIST ) { + msg = LB_GETTEXT; + } else { + msg = CB_GETLBTEXT; + } + } + cnt = (int)SendMessage( bl->hWnd, msg, inx, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (s) + strncpy( s, mswTmpBuff, siz ); + if (bl->last >= 0) { + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + bl->last, 0L ); + if ( ldp==(listData*)LB_ERR ) + ldp = NULL; + } else { + ldp = NULL; + } +EMPTY: + if (itemContextRef) + *itemContextRef = (ldp?ldp->itemContext:NULL); + if (listContextRef) + *listContextRef = bl->data; + return bl->last; +} + +wBool_t wListSetValues( + wList_p b, + wIndex_t inx, + const char * labelStr, + wIcon_p bm, + void * itemData ) +{ + listData * ldp; + WORD curSel; + ldp = (listData*)malloc( sizeof *ldp ); + ldp->itemContext = itemData; + ldp->bm = bm; + ldp->selected = FALSE; + if ( (b->option&BL_MANY) == 0 ) + curSel = (WORD)SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_GETCURSEL:CB_GETCURSEL, + (WPARAM)0, + (DWORD)0L ); + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_DELETESTRING:CB_DELETESTRING, + (WPARAM)inx, + (DWORD)0L ); + inx = (wIndex_t)SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_INSERTSTRING:CB_INSERTSTRING, + (WPARAM)inx, + (DWORD)(LPSTR)labelStr ); + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETITEMDATA:CB_SETITEMDATA, + (WPARAM)inx, + (DWORD)ldp ); + if ( (b->option&BL_MANY) == 0 && curSel == (WORD)inx) + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETCURSEL:CB_SETCURSEL, + (WPARAM)inx, + (DWORD)0L ); + /*if (b->option&BL_ICON)*/ + InvalidateRect( b->hWnd, NULL, FALSE ); + return TRUE; +} + + +void wListDelete( + wList_p b, + wIndex_t inx ) +{ + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_DELETESTRING:CB_DELETESTRING, + (WPARAM)inx, + (DWORD)0L ); +} + + +wIndex_t wListGetCount( + wList_p bl ) +{ + bl->count = (int)SendMessage( bl->hWnd, (UINT)bl->type==B_LIST?LB_GETCOUNT:CB_GETCOUNT, 0, 0L ); + return bl->count; +} + + +void * wListGetItemContext( + wList_p bl, + wIndex_t inx ) +{ + listData * ldp; + wListGetCount(bl); + if ( inx < 0 || inx >= bl->count ) return NULL; + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + inx, 0L ); + return ((ldp&&ldp!=(void*)LB_ERR)?ldp->itemContext:NULL); +} + + +wBool_t wListGetItemSelected( + wList_p bl, + wIndex_t inx ) +{ + listData * ldp; + wListGetCount(bl); + if ( inx < 0 || inx >= bl->count ) return FALSE; + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + inx, 0L ); + return ((ldp&&ldp!=(void*)LB_ERR)?ldp->selected:FALSE); +} + + +wIndex_t wListGetSelectedCount( + wList_p bl ) +{ + wIndex_t selcnt, inx; + wListGetCount(bl); + for ( selcnt=inx=0; inx<bl->count; inx++ ) + if ( wListGetItemSelected( bl, inx ) ) + selcnt++; + return selcnt; +} + + +wIndex_t wListAddValue( + wList_p b, + const char * value, + wIcon_p bm, + void * itemContext ) +{ + int nindex; + listData * ldp; + ldp = (listData*)malloc( sizeof *ldp ); + ldp->itemContext = itemContext; + ldp->bm = bm; + ldp->selected = FALSE; + if ( value == NULL ) + value = ""; + b->count++; + nindex = (int)SendMessage( + b->hWnd, + (UINT)b->type==B_LIST?LB_ADDSTRING:CB_ADDSTRING, + (WPARAM)0, + (DWORD)value ); + if (nindex == 0) { + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETCURSEL:CB_SETCURSEL, + (WPARAM)nindex, + (DWORD)0 ); + b->last = 0; + } + SendMessage( b->hWnd, + (UINT)b->type==B_LIST?LB_SETITEMDATA:CB_SETITEMDATA, + (WPARAM)nindex, + (DWORD)ldp ); + return nindex; +} + + +int wListGetColumnWidths( + wList_p bl, + int colCnt, + wPos_t * colWidths ) +{ + wIndex_t inx; + + if ( bl->type != B_LIST ) + return 0; + if ( bl->colWidths == NULL ) + return 0; + for ( inx=0; inx<colCnt; inx++ ) { + if ( inx < bl->colCnt ) + colWidths[inx] = bl->colWidths[inx]; + else + colWidths[inx] = 0; + } + return bl->colCnt; +} + + +static void listSetBusy( + wControl_p b, + BOOL_T busy) +{ + wList_p bl = (wList_p)b; + + EnableWindow( bl->hWnd, !(BOOL)busy ); + if ( bl->hScrollWnd ) + EnableWindow( bl->hScrollWnd, !(BOOL)busy ); +} + +static void listShow( + wControl_p b, + BOOL_T show) +{ + wList_p bl = (wList_p)b; + + ShowWindow( bl->hWnd, show?SW_SHOW:SW_HIDE ); + if ( bl->hScrollWnd && bl->maxWidth > bl->w ) + ShowWindow( bl->hScrollWnd, show?SW_SHOW:SW_HIDE ); +#ifdef SHOW_DOES_SETFOCUS + if ( show && (bl->option&BO_READONLY)==0 ) + hWnd = SetFocus( bl->hWnd ); +#endif +} + +static void listSetPos( + wControl_p b, + wPos_t x, + wPos_t y ) +{ + wList_p bl = (wList_p)b; + wPos_t x1, y1; + RECT rect; + + bl->x = x1 = x; + bl->y = y1 = y; + if ( bl->colTitles ) + y1 += listTitleHeight; + if (!SetWindowPos( b->hWnd, HWND_TOP, x1, y1, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("listSetPos"); + if ( bl->hScrollWnd && bl->maxWidth > bl->w ) { + GetClientRect( bl->hWnd, &rect ); + if (!SetWindowPos( bl->hScrollWnd, HWND_TOP, x1, y1+rect.bottom+2, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("listSetPos2"); + } +} + + +static void listRepaintLabel( + HWND hWnd, + wControl_p b ) +{ + wList_p bl = (wList_p)b; + HDC hDc; + RECT rc; + HFONT hFont; + HPEN hPen0, hPen1, hPen2, hPen3; + HBRUSH hBrush; + const char * * title; + int inx; + int start; + wPos_t colWidth; + + mswRepaintLabel( hWnd, b ); + if ( bl->colTitles == NULL ) + return; + hDc = GetDC( hWnd ); + start = bl->x-bl->scrollPos+2; + rc.top = bl->y; + rc.bottom = bl->y+listTitleHeight; + rc.left = bl->x-1; + rc.right = bl->x+bl->w; + hBrush = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) ); + FillRect( hDc, &rc, hBrush ); + SetBkColor( hDc, GetSysColor( COLOR_BTNFACE ) ); + + hFont = SelectObject( hDc, mswLabelFont ); + hPen1 = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_BTNTEXT ) ); + hPen2 = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_BTNHIGHLIGHT ) ); + hPen3 = CreatePen( PS_SOLID, 0, GetSysColor( COLOR_BTNSHADOW ) ); + hPen0 = SelectObject( hDc, hPen1 ); + MoveTo( hDc, rc.left, rc.top ); + LineTo( hDc, rc.right, rc.top ); + LineTo( hDc, rc.right, rc.bottom ); + LineTo( hDc, rc.left, rc.bottom ); + LineTo( hDc, rc.left, rc.top ); + SelectObject( hDc, hPen2 ); + MoveTo( hDc, rc.left+1, rc.bottom-1 ); + LineTo( hDc, rc.left+1, rc.top+1 ); + LineTo( hDc, rc.right-1, rc.top+1 ); + SelectObject( hDc, hPen3 ); + MoveTo( hDc, rc.left+2, rc.bottom-1 ); + LineTo( hDc, rc.right-1, rc.bottom-1 ); + LineTo( hDc, rc.right-1, rc.top+1 ); + rc.top += 2; + rc.bottom -= 1; + for ( inx=0,title=bl->colTitles; inx<bl->colCnt&&*title&&start<bl->x+bl->w; inx++ ) { + colWidth = bl->colWidths[inx]; + if ( start+colWidth >= 3 ) { + rc.left = start; + if ( rc.left < bl->x+2 ) + rc.left = bl->x+2; + rc.right = start+colWidth; + if ( rc.right > bl->x+bl->w-1 ) + rc.right = bl->x+bl->w-1; + ExtTextOut( hDc, start+1, rc.top+0, + ETO_CLIPPED|ETO_OPAQUE, &rc, + *title, strlen(*title), NULL ); + if ( start-bl->x >= 3 ) { + SelectObject( hDc, hPen1 ); + MoveTo( hDc, start-1, rc.top-1 ); + LineTo( hDc, start-1, rc.bottom+3 ); + SelectObject( hDc, hPen2 ); + MoveTo( hDc, start, rc.top ); + LineTo( hDc, start, rc.bottom+1 ); + SelectObject( hDc, hPen3 ); + MoveTo( hDc, start-2, rc.top ); + LineTo( hDc, start-2, rc.bottom+1 ); + } + } + title++; + start += colWidth; + } + SelectObject( hDc, hPen0 ); + SelectObject( hDc, hFont ); + DeleteObject( hBrush ); + DeleteObject( hPen1 ); + DeleteObject( hPen2 ); + DeleteObject( hPen3 ); +} + + +#ifdef LATER +static void listHandleSelectionState( LPDRAWITEMSTRUCT lpdis, LPRECT rc ) +{ + int oldROP; + oldROP = SetROP2( lpdis->hDC, R2_NOT ); + Rectangle( lpdis->hDC, rc->left, rc->top, rc->right, rc->bottom ); + SetROP2( lpdis->hDC, oldROP ); + /*InvertRect( lpdis->hDC, rc );*/ +} +#endif + +static void listHandleFocusState( LPDRAWITEMSTRUCT lpdis, LPRECT rc ) +{ + DrawFocusRect( lpdis->hDC, rc ); +} + + +LRESULT listProc( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wList_p bl = (wList_p)b; + int cnt, inx, selected; + long len; + listData * ldp; + HDC hDc; + LPMEASUREITEMSTRUCT lpmis; + TEXTMETRIC tm; + LPDRAWITEMSTRUCT lpdis; + RECT rc, rc1; + char * cp0, * cp1; + wPos_t colWidth, x; + int nPos; + HFONT hFont; + HPEN hPen; + HBRUSH hBrush; + WPARAM notification; + COLORREF col; + + if (bl) switch( message ) { + + case WM_COMMAND: + notification = WCMD_PARAM_NOTF; + switch (bl->type) { + case B_LIST: + switch (notification) { + case LBN_SELCHANGE: + case LBN_DBLCLK: + if ( (bl->option&BL_DBLCLICK)!=0 ? + notification!=LBN_DBLCLK : + notification==LBN_DBLCLK ) + break; + if ( (bl->option&BL_MANY) ) { + wListGetCount(bl); + for ( inx=0; inx<bl->count; inx++ ) { + ldp = (listData*)SendMessage( bl->hWnd, LB_GETITEMDATA, inx, 0L ); + if ( ldp != NULL && ldp != (void*)LB_ERR ) { + selected = ((long)SendMessage( bl->hWnd, LB_GETSEL, inx, 0L ) != 0L ); + if ( selected != ldp->selected ) { + ldp->selected = selected; + if ( selected ) { + bl->last = inx; + cnt = (int)SendMessage( bl->hWnd, LB_GETTEXT, bl->last, (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + } else { + mswTmpBuff[0] = '\0'; + } + if ( bl->action ) + bl->action( inx, mswTmpBuff, selected?1:2, bl->data, ldp->itemContext ); + if ( selected && bl->valueP ) + *bl->valueP = bl->last; + } + } + } + } else { + bl->last = (int)SendMessage( bl->hWnd, LB_GETCURSEL, 0, 0L ); + cnt = (int)SendMessage( bl->hWnd, LB_GETTEXT, bl->last, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if (bl->action) { + ldp = (listData*)SendMessage( bl->hWnd, LB_GETITEMDATA, + bl->last, 0L ); + bl->action( bl->last, mswTmpBuff, 1, bl->data, + ((bl->last>=0&&ldp&&ldp!=(void*)LB_ERR)?ldp->itemContext:NULL) ); + } + if (bl->valueP) { + *bl->valueP = bl->last; + } + } + break; + + case LBN_KILLFOCUS: + if ( ( bl->option&BL_MANY ) == 0 && + bl->last != (int)SendMessage( bl->hWnd, LB_GETCURSEL, 0, 0L ) ) + (void)SendMessage( bl->hWnd, LB_SETCURSEL, bl->last, 0L ); + break; + } + break; + + case B_DROPLIST: + case B_COMBOLIST: + switch (notification) { + case CBN_SELCHANGE: + case CBN_DBLCLK: + if ( (bl->type == B_DROPLIST) || + ( (bl->option&BL_DBLCLICK)!=0 ? + notification!=CBN_DBLCLK : + notification==CBN_DBLCLK) ) + break; + + case CBN_CLOSEUP: + bl->last = (int)SendMessage( bl->hWnd, CB_GETCURSEL, 0, 0L ); + if (bl->last < 0) + break; + if (bl->action) { + cnt = (int)SendMessage( bl->hWnd, CB_GETLBTEXT, bl->last, + (DWORD)(LPSTR)mswTmpBuff ); + ldp = (listData*)SendMessage( bl->hWnd, CB_GETITEMDATA, + bl->last, 0L ); + mswTmpBuff[cnt] = '\0'; + bl->action( bl->last, mswTmpBuff, 1, bl->data, + ((bl->last>=0&&ldp&&ldp!=(void*)LB_ERR)?ldp->itemContext:NULL) ); + } + if (bl->valueP) { + *bl->valueP = bl->last; + } + mswAllowBalloonHelp = TRUE; + /*SendMessage( bl->bWnd, CB_SETCURSEL, bl->last, 0L );*/ + break; + + case CBN_KILLFOCUS: + inx = (int)SendMessage( bl->hWnd, CB_GETCURSEL, 0, 0L ); + if ( bl->last != inx ) + (void)SendMessage( bl->hWnd, CB_SETCURSEL, bl->last, 0L ); + break; + + case CBN_DROPDOWN: + mswAllowBalloonHelp = FALSE; + break; + + case CBN_EDITCHANGE: + bl->last = -1; + if (bl->action) { + cnt = (int)SendMessage( bl->hWnd, WM_GETTEXT, sizeof mswTmpBuff, + (DWORD)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + bl->action( -1, mswTmpBuff, 1, bl->data, NULL ); + } + break; + } + break; + } + break; + + case WM_MEASUREITEM: + lpmis = (LPMEASUREITEMSTRUCT)lParam; + hDc = GetDC( hWnd ); + if ( bl->type == B_LIST ) + hFont = SelectObject( hDc, mswLabelFont ); + GetTextMetrics( hDc, &tm ); + lpmis->itemHeight = tm.tmHeight; + if ( bl->type == B_LIST ) + SelectObject( hDc, hFont ); + ReleaseDC( hWnd, hDc ); + break; + + case WM_DRAWITEM: + lpdis = (LPDRAWITEMSTRUCT)lParam; + if (lpdis->itemID == -1) { + listHandleFocusState(lpdis, &lpdis->rcItem); + return TRUE; + } + ldp = (listData*)SendMessage( bl->hWnd, + (bl->type==B_LIST?LB_GETITEMDATA:CB_GETITEMDATA), + lpdis->itemID, 0L ); + rc = lpdis->rcItem; + if (lpdis->itemAction & (ODA_DRAWENTIRE|ODA_SELECT|ODA_FOCUS)) { + if( bl->type == B_LIST ) + hFont = SelectObject( lpdis->hDC, mswLabelFont ); + cnt = (int)SendMessage( lpdis->hwndItem, + (bl->type==B_LIST?LB_GETTEXT:CB_GETLBTEXT), + lpdis->itemID, (LONG)(LPSTR)mswTmpBuff ); + mswTmpBuff[cnt] = '\0'; + if ( lpdis->itemState & ODS_SELECTED ) { + SetTextColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHTTEXT ) ); + SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); + } else { + SetTextColor( lpdis->hDC, GetSysColor( COLOR_WINDOWTEXT ) ); + SetBkColor( lpdis->hDC, GetSysColor( COLOR_WINDOW ) ); + } + rc1 = rc; + rc1.left -= bl->scrollPos; + for ( inx=0,cp0=mswTmpBuff; inx<bl->colCnt&&cp0&&rc1.left<rc.right; inx++ ) { + if ( inx>=bl->colCnt-1 || (cp1=strchr(cp0,'\t')) == NULL ) { + len = strlen( cp0 ); + cp1=cp0 + len; // JBB, to avoid an MSC error below where cp1 has not been defined. + } else { + len = cp1-cp0; + cp1 ++; + } + if ( bl->colWidths ) { + colWidth = bl->colWidths[inx]; + } else { + colWidth = rc.right; + } + if ( inx == 0 && ldp && ldp!=(void*)LB_ERR && ldp->bm ) { + if (mswPalette) { + SelectPalette( lpdis->hDC, mswPalette, 0 ); + cnt = RealizePalette( lpdis->hDC ); + } + hPen = SelectObject( lpdis->hDC, CreatePen( PS_SOLID, 0, GetSysColor( COLOR_WINDOW ) ) ); + hBrush = SelectObject( lpdis->hDC, CreateSolidBrush( GetSysColor( COLOR_WINDOW ) ) ); + Rectangle( lpdis->hDC, rc1.left, rc1.top, rc1.right, rc1.bottom ); + DeleteObject( SelectObject( lpdis->hDC, hPen ) ); + DeleteObject( SelectObject( lpdis->hDC, hBrush ) ); + + col = RGB( (ldp->bm->colormap[ 1 ]).rgbRed, + (ldp->bm->colormap[ 1 ]).rgbGreen, + (ldp->bm->colormap[ 1 ]).rgbBlue ); + mswDrawIcon( lpdis->hDC, rc1.left+2, rc.top+0, ldp->bm, 0, col, col); + + rc1.left += ldp->bm->w+6; + colWidth -= ldp->bm->w+6; + } + if ( inx>=bl->colCnt-1 || (rc1.right = rc1.left + colWidth) > rc.right ) + rc1.right = rc.right; + if ( rc1.right > 0 && rc1.left+3 < rc.right ) { + ExtTextOut( lpdis->hDC, rc1.left+3, rc1.top+1, + ETO_CLIPPED | ETO_OPAQUE, &rc1, + (LPSTR)cp0, (int)len, NULL ); + } + rc1.left = rc1.right; + cp0 = cp1; + } + if ( lpdis->itemState & ODS_SELECTED ) { + SetTextColor( lpdis->hDC, GetSysColor( COLOR_WINDOWTEXT ) ); + SetBkColor( lpdis->hDC, GetSysColor( COLOR_WINDOW ) ); + } + if (lpdis->itemState & ODS_FOCUS) { + DrawFocusRect( lpdis->hDC, &rc ); + } + if ( bl->type == B_LIST) + SelectObject( lpdis->hDC, hFont ); + return TRUE; + } + + break; + + case WM_HSCROLL: + len = ((long)bl->maxWidth)-((long)bl->w); + if ( len <= 0 ) + return 0; + switch ( WSCROLL_PARAM_CODE ) { + case SB_LEFT: + if ( bl->scrollPos == 0 ) + return 0; + bl->scrollPos = 0; + break; + case SB_LINELEFT: + case SB_PAGELEFT: + if ( bl->scrollPos == 0 ) + return 0; + for ( inx=colWidth=0; inx<bl->colCnt; inx++ ) { + if ( colWidth+bl->colWidths[inx] >= bl->scrollPos ) { + bl->scrollPos = colWidth; + break; + } + colWidth += bl->colWidths[inx]; + } + break; + case SB_LINERIGHT: + case SB_PAGERIGHT: + if ( bl->scrollPos >= len ) + return 0; + for ( inx=colWidth=0; inx<bl->colCnt; inx++ ) { + if ( colWidth >= bl->scrollPos ) { + bl->scrollPos = colWidth+bl->colWidths[inx]; + break; + } + colWidth += bl->colWidths[inx]; + } + break; + case SB_RIGHT: + if ( bl->scrollPos >= len ) + return 0; + bl->scrollPos = (int)len; + break; + case SB_THUMBTRACK: + return 0; + case SB_THUMBPOSITION: + nPos = (int)WSCROLL_PARAM_NPOS; + bl->scrollPos = (int)(len*nPos/100); + break; + case SB_ENDSCROLL: + return 0; + } + if ( bl->scrollPos > len ) bl->scrollPos = (int)len; + if ( bl->scrollPos < 0 ) bl->scrollPos = 0; + nPos = (int)(((long)bl->scrollPos)*100L/len+0.5); + SetScrollPos( bl->hScrollWnd, SB_CTL, nPos, TRUE ); + InvalidateRect( bl->hWnd, NULL, FALSE ); + listRepaintLabel( ((wControl_p)(bl->parent))->hWnd, (wControl_p)bl ); + return 0; + + case WM_LBUTTONDOWN: + if ( bl->type != B_LIST ) + break; + if ( bl->colCnt <= 1 ) + break; + x = bl->dragPos = LOWORD(lParam)+bl->scrollPos-4; + bl->dragCol = -1; + for ( inx=0; inx<bl->colCnt; inx++ ) { + x -= bl->colWidths[inx]; + if ( x < -5 ) break; + if ( x <= 0 ) { bl->dragCol = inx; break; } + if ( x > bl->colWidths[inx+1] ) continue; + if ( x <= 10 ) { bl->dragCol = inx; break; } + } + if ( bl->dragCol >= 0 ) + bl->dragColWidth = bl->colWidths[inx]; + return 0L; + +#ifdef LATER + case WM_MOUSEMOVE: + if ( (wParam&MK_LBUTTON) == 0 ) + break; + if ( bl->type != B_LIST ) + break; + if ( bl->colCnt <= 1 ) + break; + x = LOWORD(lParam)+bl->scrolPos; + for ( inx=0; inx<bl->colCnt; inx++ ) { + x -= bl->colWidths[inx]; + if ( x <= 0 ) + break; + } + return 0L; +#endif + + case WM_MOUSEMOVE: + if ( (wParam&MK_LBUTTON) == 0 ) + break; + case WM_LBUTTONUP: + if ( bl->type != B_LIST ) + break; + if ( bl->colCnt <= 1 ) + break; + if ( bl->dragCol < 0 ) + break; + x = LOWORD(lParam)+bl->scrollPos-4-bl->dragPos; /* WIN32??? */ + bl->colWidths[bl->dragCol] = bl->dragColWidth+x; + if ( bl->colWidths[bl->dragCol] < 0 ) + bl->colWidths[bl->dragCol] = 0; + for ( bl->maxWidth=inx=0; inx<bl->colCnt; inx++ ) + bl->maxWidth += bl->colWidths[inx]; + if ( bl->maxWidth <= bl->w ) { + x = bl->w - bl->maxWidth; + bl->colWidths[bl->colCnt-1] += x; + bl->maxWidth = bl->w; + bl->scrollPos = 0; + } else { + if ( bl->scrollPos+bl->w > bl->maxWidth ) { + bl->scrollPos = bl->maxWidth - bl->w; + } + } + InvalidateRect( bl->hWnd, NULL, FALSE ); + listRepaintLabel( ((wControl_p)(bl->parent))->hWnd, (wControl_p)bl ); + return 0L; + + } + + return DefWindowProc( hWnd, message, wParam, lParam ); +} + +long FAR PASCAL _export pushList( + HWND hWnd, + UINT message, + UINT wParam, + LONG lParam ) +{ + /* Catch <Return> and cause focus to leave control */ +#ifdef WIN32 + long inx = GetWindowLong( hWnd, GWL_ID ); +#else + short inx = GetWindowWord( hWnd, GWW_ID ); +#endif + wControl_p b = mswMapIndex( inx ); + + switch (message) { + case WM_CHAR: + if ( b != NULL) { + switch( WCMD_PARAM_ID ) { + case 0x0D: + case 0x1B: + case 0x09: + SetFocus( ((wControl_p)(b->parent))->hWnd ); + SendMessage( ((wControl_p)(b->parent))->hWnd, WM_CHAR, + wParam, lParam ); + /*SendMessage( ((wControl_p)(b->parent))->hWnd, WM_COMMAND, + inx, MAKELONG( hWnd, EN_KILLFOCUS ) );*/ + return 0L; + } + } + break; + } + return CallWindowProc( oldListProc, hWnd, message, wParam, lParam ); +} + +long FAR PASCAL _export pushCombo( + HWND hWnd, + UINT message, + UINT wParam, + LONG lParam ) +{ + /* Catch <Return> and cause focus to leave control */ +#ifdef WIN32 + long inx = GetWindowLong( hWnd, GWL_ID ); +#else + short inx = GetWindowWord( hWnd, GWW_ID ); +#endif + wControl_p b = mswMapIndex( inx ); + + switch (message) { + case WM_CHAR: + if ( b != NULL) { + switch( WCMD_PARAM_ID ) { + case 0x0D: + case 0x1B: + case 0x09: + SetFocus( ((wControl_p)(b->parent))->hWnd ); + SendMessage( ((wControl_p)(b->parent))->hWnd, WM_CHAR, + wParam, lParam ); + /*SendMessage( ((wControl_p)(b->parent))->hWnd, WM_COMMAND, + inx, MAKELONG( hWnd, EN_KILLFOCUS ) );*/ + return 0L; + } + } + break; + } + return CallWindowProc( oldComboProc, hWnd, message, wParam, lParam ); +} + +static callBacks_t listCallBacks = { + listRepaintLabel, + NULL, + listProc, + listSetBusy, + listShow, + listSetPos }; + + +static wList_p listCreate( + int typ, + const char *className, + long style, + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + long *valueP, + wListCallBack_p action, + void *data, + wBool_t addFocus, + int *indexR ) +{ + wList_p b; + RECT rect; + int index; + + b = (wList_p)mswAlloc( parent, typ, mswStrdup(labelStr), sizeof *b, data, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + b->count = 0; + b->last = -1; + b->valueP = valueP; + b->labelY += 4; + b->action = action; + b->maxWidth = 0; + b->scrollPos = 0; + b->scrollH = 0; + b->dragPos = 0; + b->dragCol = -1; + + b->hWnd = CreateWindow( className, NULL, + style | WS_CHILD | WS_VISIBLE | mswGetBaseStyle(parent), b->x, b->y, + width, LIST_HEIGHT*(int)number, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(LIST)"); + return b; + } + +#ifdef CONTROL3D + Ctl3dSubclassCtl( b->hWnd ); +#endif + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + b->colCnt = 1; + b->colWidths = NULL; + b->colTitles = NULL; + + mswAddButton( (wControl_p)b, TRUE, helpStr ); + mswCallBacks[typ] = &listCallBacks; + if (addFocus) { + mswChainFocus( (wControl_p)b ); + if (b->type == B_LIST) { + newListProc = MakeProcInstance( (XWNDPROC)pushList, mswHInst ); + oldListProc = (XWNDPROC)GetWindowLong( b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newListProc ); + } else { + newComboProc = MakeProcInstance( (XWNDPROC)pushCombo, mswHInst ); + oldComboProc = (XWNDPROC)GetWindowLong( b->hWnd, GWL_WNDPROC ); + SetWindowLong( b->hWnd, GWL_WNDPROC, (LONG)newComboProc ); + } + } + if ( indexR ) + *indexR = index; + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + return b; +} + + +wList_p wListCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + int colCnt, + wPos_t * colWidths, + wBool_t * colRightJust, + const char * * colTitles, + long *valueP, + wListCallBack_p action, + void *data ) +{ + long bs; + wList_p bl; + static int dbu = 0; + RECT rect; + int index; + int i; + + bs = LBS_NOTIFY | WS_VSCROLL | WS_BORDER | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS; + if (option & BL_MANY) + bs |= LBS_MULTIPLESEL|LBS_EXTENDEDSEL; + if (option & BL_SORT) + bs |= LBS_SORT; + if ( colCnt > 1 ) + bs |= WS_HSCROLL; + if ( colTitles ) { + y += listTitleHeight; + number -= 1; + } + bl = listCreate( B_LIST, "LISTBOX", bs, parent, x, y, helpStr, + labelStr, option, number, width, valueP, action, data, TRUE, &index ); + if ( colTitles ) { + bl->y -= listTitleHeight; + bl->h += listTitleHeight; + } + if ( colCnt > 1 ) { + bl->colCnt = colCnt; + bl->colWidths = (int*)malloc( colCnt * sizeof *bl->colWidths ); + bl->colRightJust = (wBool_t*)malloc( colCnt * sizeof *bl->colRightJust ); + bl->colTitles = colTitles; + bl->maxWidth = 0; + memcpy( bl->colWidths, colWidths, colCnt * sizeof *bl->colWidths ); + for ( i=0; i<colCnt; i++ ) { + bl->colWidths[i] = colWidths[i]; + bl->maxWidth += bl->colWidths[i]; + } + bl->hScrollWnd = CreateWindow( "ScrollBar", NULL, + SBS_HORZ | SBS_BOTTOMALIGN | WS_CHILD | WS_VISIBLE | mswGetBaseStyle(parent), bl->x, bl->y, + width, CW_USEDEFAULT, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (bl->hScrollWnd == NULL) + mswFail("CreateWindow(LISTSCROLL)"); + SetScrollRange( bl->hScrollWnd, SB_CTL, 0, 100, TRUE ); + GetWindowRect( bl->hScrollWnd, &rect ); + bl->scrollH = rect.bottom - rect.top+2; + } + return bl; +} + + +wList_p wDropListCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + long *valueP, + wListCallBack_p action, + void *data ) +{ + long bs; + + if ( (option&BL_EDITABLE) != 0 ) + bs = CBS_DROPDOWN; + else + bs = CBS_DROPDOWNLIST; + bs |= WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS; + if (option & BL_SORT) + bs |= CBS_SORT; + return listCreate( B_DROPLIST, "COMBOBOX", bs, parent, x, y, helpStr, + labelStr, option, number, width, valueP, action, data, TRUE, NULL ); +} + +wList_p wComboListCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + long number, + POS_T width, + long *valueP, + wListCallBack_p action, + void *data ) +{ + long bs; + + bs = CBS_SIMPLE | WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS; + if (option & BL_SORT) + bs |= CBS_SORT; + return listCreate( B_COMBOLIST, "COMBOBOX", bs, parent, x, y, helpStr, + labelStr, option, number, width, valueP, action, data, FALSE, NULL ); +} diff --git a/app/wlib/mswlib/mswmenu.c b/app/wlib/mswlib/mswmenu.c new file mode 100644 index 0000000..15053a2 --- /dev/null +++ b/app/wlib/mswlib/mswmenu.c @@ -0,0 +1,1062 @@ +#define OEMRESOURCE + +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <ctype.h> +#include <assert.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Menus + * + ***************************************************************************** + */ + +typedef enum { M_MENU, M_SEPARATOR, M_PUSH, M_LIST, M_LISTITEM, M_TOGGLE, M_RADIO } mtype_e; +typedef enum { MM_BUTT, MM_MENU, MM_BAR, MM_POPUP } mmtype_e; + +typedef struct wMenuItem_t * wMenuItem_p; + +struct radioButtonGroup { + int firstButton; /* id of first button in group */ + int lastButton; /* id of last button in group */ +}; + +/* NOTE: first field must be the same as WOBJ_COMMON */ +#define MOBJ_COMMON \ + WOBJ_COMMON \ + int index; \ + mtype_e mtype; \ + wMenu_p parentMenu; \ + wMenuItem_p mnext; + +struct wMenuItem_t { + MOBJ_COMMON + }; + +struct wMenu_t { + MOBJ_COMMON + mmtype_e mmtype; + wMenuItem_p first, last; + struct radioButtonGroup *radioGroup; + HMENU menu; + wButton_p button; + wMenuTraceCallBack_p traceFunc; + void * traceData; + }; + +struct wMenuPush_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuCallBack_p action; + long acclKey; + wBool_t enabled; + }; + +struct wMenuRadio_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuCallBack_p action; + long acclKey; + wBool_t enabled; + }; +struct wMenuToggle_t { + MOBJ_COMMON + wMenu_p mparent; + wMenuToggleCallBack_p action; + long acclKey; + wBool_t enabled; + }; + +typedef struct wMenuListItem_t * wMenuListItem_p; +struct wMenuList_t { + MOBJ_COMMON + wMenuListItem_p left, right; + wMenu_p mlparent; + int max; + int count; + wMenuListCallBack_p action; + }; + +struct wMenuListItem_t { + MOBJ_COMMON + wMenuListItem_p left, right; + wMenuListCallBack_p action; + }; + +#define UNCHECK (0) +#define CHECK (1) +#define RADIOCHECK (2) +#define RADIOUNCHECK (3) + +static HBITMAP checked; +static HBITMAP unchecked; +static HBITMAP checkedRadio; +static HBITMAP uncheckedRadio; + + +/* + ***************************************************************************** + * + * Internal Functions + * + ***************************************************************************** + */ + +char * mswStrdup( const char * str ) +{ + char * ret; + if (str) { + ret = (char*)malloc( strlen(str)+1 ); + strcpy( ret, str ); + } else + ret = NULL; + return ret; +} + +static LRESULT menuPush( + wControl_p b, + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam ) +{ + wMenuItem_p m = (wMenuItem_p)b; + wBool_t set; + + mswAllowBalloonHelp = TRUE; + + switch( message ) { + + case WM_COMMAND: + + switch (m->mtype) { + default: + mswFail( "pushMenu" ); + break; + case M_PUSH: + if (((wMenuPush_p)m)->action) + ((wMenuPush_p)m)->action(((wMenuPush_p)m)->data); + break; + case M_TOGGLE: + set = wMenuToggleGet((wMenuToggle_p)m); + set = !set; + wMenuToggleSet((wMenuToggle_p)m,set); + if (((wMenuToggle_p)m)->action) + ((wMenuToggle_p)m)->action(set, ((wMenuPush_p)m)->data); + break; + case M_LISTITEM: + if (((wMenuListItem_p)m)->action) + ((wMenuListItem_p)m)->action(0, "", ((wMenuListItem_p)m)->data); + break; + case M_RADIO: + if (((wMenuRadio_p)m)->action) + ((wMenuRadio_p)m)->action(((wMenuRadio_p)m)->data); + break; + } + return 0L; + } + if ( (m->parentMenu)->traceFunc ) { + (m->parentMenu)->traceFunc( m->parentMenu, m->labelStr, ((wMenu_p)m->parentMenu)->traceData ); + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + +static void menuDone( wControl_p b ) +{ + wMenuItem_p m = (wMenuItem_p)b; + switch ( m->mtype ) { + case M_MENU: + if ( ((wMenu_p)m)->mmtype == MM_BUTT || + ((wMenu_p)m)->mmtype == MM_POPUP ) + DestroyMenu( ((wMenu_p)m)->menu ); + break; + } +} + +static callBacks_t menuItemCallBacks = { + NULL, + menuDone, + menuPush }; + + +static wMenuItem_p createMenuItem( + wMenu_p m, + mtype_e mtype, + const char * helpStr, + const char * labelStr, + int size ) +{ + wMenuItem_p mi; + + mi = (wMenuItem_p)calloc( 1, size ); + mi->type = B_MENUITEM; + /*mi->messageProc = menuPush;*/ + mi->index = mswRegister( (wControl_p)mi ); + mi->mtype = mtype; + if (m) { + if (m->last != NULL) { + m->last->mnext = mi; + } else { + m->first = m->last = mi; + } + m->last = mi; + } + mi->mnext = NULL; + mi->labelStr = mswStrdup( labelStr ); +// if (helpStr != NULL) { +// char *string; +// string = malloc( strlen(helpStr) + 1 ); +// strcpy( string, helpStr ); +// /*xv_set(mi->menu_item, XV_HELP_DATA, string, 0 );*/ +// } + mswCallBacks[B_MENUITEM] = &menuItemCallBacks; + return mi; +} + +/* + ***************************************************************************** + * + * Accelerators + * + ***************************************************************************** + */ + + +typedef struct { + long acclKey; + wMenuPush_p mp; + wAccelKeyCallBack_p action; + wAccelKey_e key; + void * data; + } acclTable_t, *acclTable_p; +dynArr_t acclTable_da; +#define acclTable(N) DYNARR_N( acclTable_t, acclTable_da, N ) + + +int mswMenuAccelerator( + wWin_p win, + long acclKey ) +{ + acclTable_p at; + if ( ((wControl_p)win)->type != W_MAIN && + ((wControl_p)win)->type != W_POPUP ) + return 0; + for ( at = &acclTable(0); at<&acclTable(acclTable_da.cnt); at++ ) { + if (at->acclKey == acclKey) { + if (at->mp) { + if (at->mp->enabled && at->mp->action) + at->mp->action(at->mp->data); + return 1; + } else if (at->action) { + at->action( at->key, at->data ); + return 1; + } else { + return 0; + } + } + } + return 0; +} + + + +static long acclKeyMap[] = { + 0, /* wAccelKey_None, */ + VK_DELETE, /* wAccelKey_Del, */ + VK_INSERT, /* wAccelKey_Ins, */ + VK_HOME, /* wAccelKey_Home, */ + VK_END, /* wAccelKey_End, */ + VK_PRIOR, /* wAccelKey_Pgup, */ + VK_NEXT, /* wAccelKey_Pgdn, */ + VK_UP, /* wAccelKey_Up, */ + VK_DOWN, /* wAccelKey_Down, */ + VK_RIGHT, /* wAccelKey_Right, */ + VK_LEFT, /* wAccelKey_Left, */ + VK_BACK, /* wAccelKey_Back, */ + VK_F1, /* wAccelKey_F1, */ + VK_F2, /* wAccelKey_F2, */ + VK_F3, /* wAccelKey_F3, */ + VK_F4, /* wAccelKey_F4, */ + VK_F5, /* wAccelKey_F5, */ + VK_F6, /* wAccelKey_F6, */ + VK_F7, /* wAccelKey_F7, */ + VK_F8, /* wAccelKey_F8, */ + VK_F9, /* wAccelKey_F9, */ + VK_F10, /* wAccelKey_F10, */ + VK_F11, /* wAccelKey_F11, */ + VK_F12 /* wAccelKey_F12, */ + }; + + +void wAttachAccelKey( + wAccelKey_e key, + int modifier, + wAccelKeyCallBack_p action, + void * data ) +{ + acclTable_t * ad; + if ( key < 1 || key > wAccelKey_F12 ) { + mswFail( "wAttachAccelKey: key out of range" ); + return; + } + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + ad = &acclTable(acclTable_da.cnt-1); + ad->acclKey = acclKeyMap[key] | (modifier<<8); + ad->key = key; + ad->action = action; + ad->data = data; + ad->mp = NULL; +} + +/* + ***************************************************************************** + * + * Menu Item Create + * + ***************************************************************************** + */ + +HBITMAP GetMyCheckBitmaps(UINT fuCheck) +{ + COLORREF crBackground; /* background color */ + HBRUSH hbrBackground; /* background brush */ + HBRUSH hbrTargetOld; /* original background brush */ + HDC hdcSource; /* source device context */ + HDC hdcTarget; /* target device context */ + HBITMAP hbmpCheckboxes; /* handle to check-box bitmap */ + BITMAP bmCheckbox; /* structure for bitmap data */ + HBITMAP hbmpSourceOld; /* handle to original source bitmap */ + HBITMAP hbmpTargetOld; /* handle to original target bitmap */ + HBITMAP hbmpCheck; /* handle to check-mark bitmap */ + RECT rc; /* rectangle for check-box bitmap */ + WORD wBitmapX; /* width of check-mark bitmap */ + WORD wBitmapY; /* height of check-mark bitmap */ + + /* Get the menu background color and create a solid brush + with that color. */ + + crBackground = GetSysColor(COLOR_MENU); + hbrBackground = CreateSolidBrush(crBackground); + + /* Create memory device contexts for the source and + destination bitmaps. */ + + hdcSource = CreateCompatibleDC((HDC) NULL); + hdcTarget = CreateCompatibleDC(hdcSource); + + /* Get the size of the system default check-mark bitmap and + create a compatible bitmap of the same size. */ + + wBitmapX = GetSystemMetrics(SM_CXMENUCHECK); + wBitmapY = GetSystemMetrics(SM_CYMENUCHECK); + + hbmpCheck = CreateCompatibleBitmap(hdcSource, wBitmapX, + wBitmapY); + + /* Select the background brush and bitmap into the target DC. */ + + hbrTargetOld = SelectObject(hdcTarget, hbrBackground); + hbmpTargetOld = SelectObject(hdcTarget, hbmpCheck); + + /* Use the selected brush to initialize the background color + of the bitmap in the target device context. */ + + PatBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, PATCOPY); + + /* Load the predefined check box bitmaps and select it + into the source DC. */ + + hbmpCheckboxes = LoadBitmap((HINSTANCE) NULL, + (LPTSTR) OBM_CHECKBOXES); + + hbmpSourceOld = SelectObject(hdcSource, hbmpCheckboxes); + + /* Fill a BITMAP structure with information about the + check box bitmaps, and then find the upper-left corner of + the unchecked check box or the checked check box. */ + + GetObject(hbmpCheckboxes, sizeof(BITMAP), &bmCheckbox); + + switch( fuCheck ) { + + case UNCHECK: + rc.left = 0; + rc.right = (bmCheckbox.bmWidth / 4); + rc.top = 0; + rc.bottom = (bmCheckbox.bmHeight / 3); + break; + case CHECK: + rc.left = (bmCheckbox.bmWidth / 4); + rc.right = (bmCheckbox.bmWidth / 4) * 2; + rc.top = 0; + rc.bottom = (bmCheckbox.bmHeight / 3); + break; + case RADIOCHECK: + rc.left = (bmCheckbox.bmWidth / 4); + rc.right = (bmCheckbox.bmWidth / 4) * 2; + rc.top = (bmCheckbox.bmHeight / 3) + 1; + rc.bottom = (bmCheckbox.bmHeight / 3) * 2; + break; + case RADIOUNCHECK: + rc.top = (bmCheckbox.bmHeight / 3) + 1; + rc.bottom = (bmCheckbox.bmHeight / 3) * 2; + rc.left = 0; + rc.right = (bmCheckbox.bmWidth / 4); + + break; + } + + /* Copy the appropriate bitmap into the target DC. If the + check-box bitmap is larger than the default check-mark + bitmap, use StretchBlt to make it fit; otherwise, just + copy it. */ + + if (((rc.right - rc.left) > (int) wBitmapX) || + ((rc.bottom - rc.top) > (int) wBitmapY)) + { + StretchBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, + hdcSource, rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top, SRCCOPY); + } + + else + { + BitBlt(hdcTarget, 0, 0, rc.right - rc.left, + rc.bottom - rc.top, + hdcSource, rc.left, rc.top, SRCCOPY); + } + + /* Select the old source and destination bitmaps into the + source and destination DCs, and then delete the DCs and + the background brush. */ + + SelectObject(hdcSource, hbmpSourceOld); + SelectObject(hdcTarget, hbrTargetOld); + hbmpCheck = SelectObject(hdcTarget, hbmpTargetOld); + + DeleteObject(hbrBackground); + DeleteObject(hdcSource); + DeleteObject(hdcTarget); + + /* Return a handle to the new check-mark bitmap. */ + + return hbmpCheck; +} + +void mswCreateCheckBitmaps() +{ + checked = GetMyCheckBitmaps( CHECK ); + unchecked = GetMyCheckBitmaps( UNCHECK ); + checkedRadio = GetMyCheckBitmaps( RADIOCHECK ); + uncheckedRadio = GetMyCheckBitmaps( RADIOUNCHECK ); + +} + +wMenuRadio_p wMenuRadioCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wMenuCallBack_p action, + void *data ) +{ + wMenuRadio_p mi; + int rc; + char label[80]; + char *cp; + char ac; + UINT vk; + long modifier; + + mi = (wMenuRadio_p)createMenuItem( m, M_RADIO, helpStr, labelStr, sizeof *mi ); + mi->action = action; + mi->data = data; + mi->mparent = m; + mi->acclKey = acclKey; + mi->enabled = TRUE; + strcpy( label, mi->labelStr ); + modifier = 0; + if ( acclKey != 0 ) { + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + cp = label + strlen( label ); + *cp++ = '\t'; + if (acclKey & WCTL ) { + strcpy( cp, "Ctrl+" ); + cp += 5; + modifier |= WKEY_CTRL; + } + if (acclKey & WALT ) { + strcpy( cp, "Alt+" ); + cp += 4; + modifier |= WKEY_ALT; + } + if (acclKey & WSHIFT ) { + strcpy( cp, "Shift+" ); + cp += 6; + modifier |= WKEY_SHIFT; + } + *cp++ = toupper( (char)(acclKey & 0xFF) ); + *cp++ = '\0'; + ac = (char)(acclKey & 0xFF); + if (isalpha(ac)) { + ac = tolower( ac ); + } + vk = VkKeyScan( ac ); + if ( vk & 0xFF00 ) + modifier |= WKEY_SHIFT; + acclTable(acclTable_da.cnt-1).acclKey = (modifier<<8) | (vk&0x00FF); + acclTable(acclTable_da.cnt-1).mp = (wMenuPush_p)mi; + } + rc = AppendMenu( m->menu, MF_STRING, mi->index, label ); + + /* add the correct bitmaps for radio buttons */ + + rc = SetMenuItemBitmaps(m->menu, mi->index, FALSE, uncheckedRadio, checkedRadio ); + + if( m->radioGroup == NULL ) { + m->radioGroup = malloc( sizeof( struct radioButtonGroup )); + assert( m->radioGroup ); + m->radioGroup->firstButton = mi->index; + } else { + m->radioGroup->lastButton = mi->index; + } + + return mi; +} + +void wMenuRadioSetActive(wMenuRadio_p mi ) +{ + BOOL rc; + + rc = CheckMenuRadioItem( mi->mparent->menu, + mi->mparent->radioGroup->firstButton, + mi->mparent->radioGroup->lastButton, + mi->index, + MF_BYCOMMAND ); +} + + +wMenuPush_p wMenuPushCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wMenuCallBack_p action, + void *data ) +{ + wMenuPush_p mi; + int rc; + char label[80]; + char *cp; + char ac; + UINT vk; + long modifier; + + mi = (wMenuPush_p)createMenuItem( m, M_PUSH, helpStr, labelStr, sizeof *mi ); + mi->action = action; + mi->data = data; + mi->mparent = m; + mi->acclKey = acclKey; + mi->enabled = TRUE; + strcpy( label, mi->labelStr ); + modifier = 0; + if ( acclKey != 0 ) { + DYNARR_APPEND( acclTable_t, acclTable_da, 10 ); + cp = label + strlen( label ); + *cp++ = '\t'; + if (acclKey & WCTL ) { + strcpy( cp, "Ctrl+" ); + cp += 5; + modifier |= WKEY_CTRL; + } + if (acclKey & WALT ) { + strcpy( cp, "Alt+" ); + cp += 4; + modifier |= WKEY_ALT; + } + if (acclKey & WSHIFT ) { + strcpy( cp, "Shift+" ); + cp += 6; + modifier |= WKEY_SHIFT; + } + *cp++ = toupper( (char)(acclKey & 0xFF) ); + *cp++ = '\0'; + ac = (char)(acclKey & 0xFF); + if (isalpha(ac)) { + ac = tolower( ac ); + } + vk = VkKeyScan( ac ); + if ( vk & 0xFF00 ) + modifier |= WKEY_SHIFT; + acclTable(acclTable_da.cnt-1).acclKey = (modifier<<8) | (vk&0x00FF); + acclTable(acclTable_da.cnt-1).mp = mi; + } + rc = AppendMenu( m->menu, MF_STRING, mi->index, label ); + return mi; +} + + +void wMenuPushEnable( + wMenuPush_p mi, + BOOL_T enable ) +{ + EnableMenuItem( mi->mparent->menu, mi->index, + MF_BYCOMMAND|(enable?MF_ENABLED:(MF_DISABLED|MF_GRAYED)) ); + mi->enabled = enable; +} + + +wMenu_p wMenuMenuCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr ) +{ + wMenu_p mm; + int rc; + + mm = (wMenu_p)createMenuItem( NULL, M_MENU, NULL, labelStr, sizeof *mm ); + mm->menu = CreatePopupMenu(); + mm->mmtype = MM_MENU; + /*mm->parent = (wControl_p)m;*/ + mm->first = mm->last = NULL; + + rc = AppendMenu( m->menu, MF_STRING|MF_ENABLED|MF_POPUP, (UINT)mm->menu, mm->labelStr ); + + return mm; +} + +void wMenuSeparatorCreate( + wMenu_p m ) +{ + int rc; + createMenuItem( m, M_SEPARATOR, NULL, NULL, sizeof *(wMenuItem_p)NULL ); + rc = AppendMenu( m->menu, MF_SEPARATOR, (UINT)0, NULL ); +} + +/* + ***************************************************************************** + * + * Menu List + * + ***************************************************************************** + */ + + +static void appendItem( + wMenuListItem_p ml, + wMenuListItem_p mi ) +{ + mi->right = ml->right; + ml->right->left = mi; + mi->left = ml; + ml->right = mi; +} + + +static void removeItem( + wMenuListItem_p mi ) +{ + mi->left->right = mi->right; + mi->right->left = mi->left; + mi->right = mi->left = mi; +} + + +wMenuList_p wMenuListCreate( + wMenu_p m, + const char * helpStr, + int max, + wMenuListCallBack_p action ) +{ + wMenuList_p mi; + mi = (wMenuList_p)createMenuItem( m, M_LIST, helpStr, NULL, sizeof *mi ); + mi->count = 0; + mi->max = max; + mi->mlparent = m; + mi->action = action; + mi->right = mi->left = (wMenuListItem_p)mi; + return mi; +} + + +int getMlistOrigin( wMenu_p m, wMenuList_p ml ) +{ + wMenuItem_p mi; + int count; + count = 0; + for ( mi = m->first; mi != NULL; mi = mi->mnext ) { + switch( mi->mtype ) { + case M_SEPARATOR: + case M_PUSH: + case M_MENU: + count++; + break; + case M_LIST: + if (mi == (wMenuItem_p)ml) + return count; + count += ((wMenuList_p)mi)->count; + break; + default: + mswFail( "getMlistOrigin" ); + } + } + return count; +} + + +void wMenuListAdd( + wMenuList_p ml, + int index, + const char * labelStr, + void * data ) +{ + int origin; + wMenuListItem_p wl_p; + wMenuListItem_p mi; + int count; + int rc; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p!=(wMenuListItem_p)ml; count++,wl_p=wl_p->right ) { + if (wl_p->labelStr != NULL && strcmp( labelStr, wl_p->labelStr ) == 0) { + /* move item */ + if (count != index) { + RemoveMenu( ml->mlparent->menu, origin+count, MF_BYPOSITION ); + removeItem( wl_p ); + goto add; + } + ((wMenuListItem_p)wl_p)->data = data; + return; + } + } + if (ml->max > 0 && ml->count >= ml->max) { + RemoveMenu( ml->mlparent->menu, origin+ml->count-1, MF_BYPOSITION ); + wl_p = ml->left; + removeItem( ml->left ); +add: + ml->count--; + if (wl_p->labelStr ) + free( CAST_AWAY_CONST wl_p->labelStr ); + wl_p->labelStr = mswStrdup( labelStr ); + } else { + wl_p = (wMenuListItem_p)createMenuItem( NULL, M_LISTITEM, NULL, + labelStr, sizeof *wl_p ); + } + ((wMenuListItem_p)wl_p)->data = data; + ((wMenuListItem_p)wl_p)->action = ml->action; + if (index < 0 || index > ml->count) + index = ml->count; + for ( mi=(wMenuListItem_p)ml,count=0; count<index; mi=mi->right,count++); + rc = InsertMenu( ml->mlparent->menu, origin+index, + MF_BYPOSITION|MF_STRING, wl_p->index, wl_p->labelStr ); + appendItem( mi, wl_p ); + ml->count++; +} + + +void wMenuListDelete( + wMenuList_p ml, + const char * labelStr ) +{ + int origin, count; + wMenuListItem_p wl_p; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p!=(wMenuListItem_p)ml; count++,wl_p=wl_p->right ) { + if (wl_p->labelStr != NULL && strcmp( labelStr, wl_p->labelStr ) == 0) { + /* delete item */ + mswUnregister( wl_p->index ); + RemoveMenu( ml->mlparent->menu, origin+count, MF_BYPOSITION ); + removeItem( wl_p ); + ml->count--; + free( wl_p ); + return; + } + } +} + + +const char * wMenuListGet( + wMenuList_p ml, + int index, + void ** data ) +{ + int origin, count; + wMenuListItem_p wl_p; + + if (index >= ml->count) + return NULL; + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; wl_p&&count<index; count++,wl_p=wl_p->right ); + if (wl_p==NULL) + return NULL; + if ( data ) + *data = wl_p->data; + return wl_p->labelStr; +} + + +void wMenuListClear( + wMenuList_p ml ) +{ + int origin, count; + wMenuListItem_p wl_p, wl_q; + + origin = getMlistOrigin(ml->mlparent, ml); + for ( count=0,wl_p=ml->right; count<ml->count; count++,wl_p=wl_q ) { + /* delete item */ + mswUnregister( wl_p->index ); + RemoveMenu( ml->mlparent->menu, origin, MF_BYPOSITION ); + wl_q = wl_p->right; + free( wl_p ); + } + ml->count = 0; + ml->right = ml->left = (wMenuListItem_p)ml; +} + + + +wMenuToggle_p wMenuToggleCreate( + wMenu_p m, + const char * helpStr, + const char * labelStr, + long acclKey, + wBool_t set, + wMenuToggleCallBack_p action, + void * data ) +{ + wMenuToggle_p mt; + int rc; + + mt = (wMenuToggle_p)createMenuItem( m, M_TOGGLE, helpStr, labelStr, sizeof *mt ); + /*setAcclKey( m->parent, m->menu, mt->menu_item, acclKey );*/ + mt->action = action; + mt->data = data; + mt->mparent = m; + mt->enabled = TRUE; + mt->parentMenu = m; + rc = AppendMenu( m->menu, MF_STRING, mt->index, labelStr ); + wMenuToggleSet( mt, set ); + return mt; +} + + +wBool_t wMenuToggleGet( + wMenuToggle_p mt ) +{ + return (GetMenuState( mt->mparent->menu, mt->index, MF_BYCOMMAND ) & MF_CHECKED) != 0; +} + + +wBool_t wMenuToggleSet( + wMenuToggle_p mt, + wBool_t set ) +{ + wBool_t rc; + CheckMenuItem( mt->mparent->menu, mt->index, MF_BYCOMMAND|(set?MF_CHECKED:MF_UNCHECKED) ); + rc = (GetMenuState( mt->mparent->menu, mt->index, MF_BYCOMMAND ) & MF_CHECKED) != 0; + return rc; +} + +void wMenuToggleEnable( + wMenuToggle_p mt, + wBool_t enable ) +{ + EnableMenuItem( mt->mparent->menu, mt->index, + MF_BYCOMMAND|(enable?MF_ENABLED:(MF_DISABLED|MF_GRAYED)) ); + mt->enabled = enable; +} + +/* + ***************************************************************************** + * + * Menu Create + * + ***************************************************************************** + */ + + +void mswMenuMove( + wMenu_p m, + wPos_t x, + wPos_t y ) +{ + wControl_p b; + b = (wControl_p)m->parent; + if (b && b->hWnd) + if (!SetWindowPos( b->hWnd, HWND_TOP, x, y, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("mswMenuMove"); +} + + +static void pushMenuButt( + void * data ) +{ + wMenu_p m = (wMenu_p)data; + RECT rect; + mswAllowBalloonHelp = FALSE; + GetWindowRect( m->hWnd, &rect ); + TrackPopupMenu( m->menu, TPM_LEFTALIGN, rect.left, rect.bottom, + 0, ((wControl_p)(m->parent))->hWnd, NULL ); +} + + +wMenu_p wMenuCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option ) +{ + wMenu_p m; + wControl_p b; + long buttOption = 0; + const char * label = labelStr; + + if (option & BM_ICON) { + buttOption = BO_ICON; + label = "ICON"; + } + m = (wMenu_p)createMenuItem( NULL, M_MENU, helpStr, label, sizeof *m ); + m->button = wButtonCreate( parent, x, y, helpStr, labelStr, + buttOption, 0, pushMenuButt, (void*)m ); + b = (wControl_p)m->button; + m->parent = b->parent; + m->x = b->x; + m->y = b->y; + m->w = b->w; + m->h = b->h; + m->hWnd = b->hWnd; + m->helpStr = b->helpStr; + + m->menu = CreatePopupMenu(); + m->mmtype = MM_BUTT; + m->first = m->last = NULL; + + return m; +} + + +wMenu_p wMenuBarAdd( + wWin_p w, + const char * helpStr, + const char * labelStr ) +{ + HMENU menu; + wMenu_p m; + int rc; + + menu = GetMenu( ((wControl_p)w)->hWnd ); + if (menu == (HMENU)0) { + menu = CreateMenu(); + SetMenu( ((wControl_p)w)->hWnd, menu ); + } + + m = (wMenu_p)createMenuItem( NULL, M_MENU, helpStr, labelStr, sizeof *m ); + m->menu = CreateMenu(); + m->parent = w; + m->mmtype = MM_BAR; + m->first = m->last = NULL; + + rc = AppendMenu( menu, MF_STRING|MF_POPUP|MF_ENABLED, (UINT)m->menu, labelStr ); + + DrawMenuBar( ((wControl_p)w)->hWnd ); + return m; +} + + + +wMenu_p wMenuPopupCreate( + wWin_p w, + const char * labelStr ) +{ + wMenu_p m; + long buttOption = 0; + const char * label = labelStr; + + m = (wMenu_p)createMenuItem( NULL, M_MENU, NULL, label, sizeof *m ); + m->button = NULL; + m->parent = w; + m->x = 0; + m->y = 0; + m->w = 0; + m->h = 0; + m->hWnd = ((wControl_p)w)->hWnd; + m->helpStr = NULL; + + m->menu = CreatePopupMenu(); + m->mmtype = MM_POPUP; + m->first = m->last = NULL; + + return m; +} + + +void wMenuPopupShow( wMenu_p mp ) +{ + POINT pt; + GetCursorPos( &pt ); + TrackPopupMenu( mp->menu, TPM_LEFTALIGN, pt.x, pt.y, 0, mp->hWnd, NULL ); +} + +/*-----------------------------------------------------------------*/ + +void wMenuSetTraceCallBack( + wMenu_p m, + wMenuTraceCallBack_p func, + void * data ) +{ + m->traceFunc = func; + m->traceData = data; +} + +wBool_t wMenuAction( + wMenu_p m, + const char * label ) +{ + wMenuItem_p mi; + wMenuToggle_p mt; + wBool_t set; + for ( mi = m->first; mi != NULL; mi = (wMenuItem_p)mi->mnext ) { + if ( mi->labelStr != NULL && strcmp( mi->labelStr, label ) == 0 ) { + switch( mi->mtype ) { + case M_SEPARATOR: + break; + case M_PUSH: + if ( ((wMenuPush_p)mi)->enabled == FALSE ) + wBeep(); + else + ((wMenuPush_p)mi)->action( ((wMenuPush_p)mi)->data ); + break; + case M_TOGGLE: + mt = (wMenuToggle_p)mi; + if ( mt->enabled == FALSE ) { + wBeep(); + } else { + set = wMenuToggleGet( mt ); + wMenuToggleSet( mt, !set ); + mt->action( set, mt->data ); + } + break; + case M_MENU: + break; + case M_LIST: + break; + default: + fprintf(stderr, "Oops: wMenuAction\n"); + } + return TRUE; + } + } + return FALSE; +} diff --git a/app/wlib/mswlib/mswmisc.c b/app/wlib/mswlib/mswmisc.c new file mode 100644 index 0000000..fc1dbe6 --- /dev/null +++ b/app/wlib/mswlib/mswmisc.c @@ -0,0 +1,2778 @@ +/** \file mswmisc.c + * Basic windows functions and main entry point for application. + * + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/wlib/mswlib/mswmisc.c,v 1.28 2010-04-28 04:04:38 dspagnol Exp $ + */ + +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2005 Dave Bullis, 2009 Martin Fischer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define _WIN32_WINNT 0x0500 +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <stdio.h> +#include <assert.h> +#include <htmlhelp.h> +#include "mswint.h" +#include "i18n.h" + +#if _MSC_VER > 1300 + #define stricmp _stricmp + #define strnicmp _strnicmp + #define strdup _strdup +#endif + +#define OFN_LONGFILENAMES 0x00200000L + +char * mswStrdup( const char * ); + +#define PAUSE_TIMER (901) +#define ALARM_TIMER (902) +#define BALLOONHELP_TIMER (903) +#define TRIGGER_TIMER (904) + +#define WANT_LITTLE_LABEL_FONT + +#ifndef WANT_LITTLE_LABEL_FONT +#define LABELFONTDECL +#define LABELFONTSELECT +#define LABELFONTRESET +#else +#define LABELFONTDECL HFONT hFont; +#define LABELFONTRESET if (!mswThickFont) {SelectObject( hDc, hFont );} +#define LABELFONTSELECT if (!mswThickFont) {hFont = SelectObject( hDc, mswLabelFont );} +#endif + +/* + * EXPORTED VARIABLES + */ + +long debugWindow = 0; +HINSTANCE mswHInst; +HWND mswHWnd = (HWND)0; + +const char *mswDrawWindowClassName = "DRAWWINDOW"; +char mswTmpBuff[1024]; +int mswEditHeight; +int mswAllowBalloonHelp = TRUE; +int mswGroupStyle; +HFONT mswOldTextFont; +HFONT mswLabelFont; +long mswThickFont = 1; +double mswScale = 1.0; + +callBacks_t *mswCallBacks[CALLBACK_CNT]; + +void closeBalloonHelp( void ); +static wControl_p getControlFromCursor( HWND, wWin_p * ); +/* + * LOCAL VARIABLES + */ + +struct wWin_t { + WOBJ_COMMON + wPos_t lastX, lastY; + wPos_t padX, padY; + wControl_p first, last; + wWinCallBack_p winProc; + BOOL_T busy; +#ifdef OWNERICON + HBITMAP wicon_bm; + wPos_t wicon_w, wicon_h; +#endif + DWORD baseStyle; + wControl_p focusChainFirst; + wControl_p focusChainLast; + char * nameStr; + wBool_t centerWin; + DWORD style; + int isBusy; + int pendingShow; + int modalLevel; + }; + +static needToDoPendingShow = FALSE; + +/* System metrics: */ +static int mTitleH; +static int mFixBorderW; +static int mFixBorderH; +static int mResizeBorderW; +static int mResizeBorderH; +static int mMenuH; +static int screenWidth = 0, screenHeight = 0; + +wWin_p mswWin = NULL; +wWin_p winFirst, winLast; + +static long count51 = 0; + +static UINT alarmTimer; +static UINT pauseTimer; +static UINT balloonHelpTimer = (UINT)0; +static UINT triggerTimer; + +static UINT balloonHelpTimeOut = 500; +static wControl_p balloonHelpButton = NULL; +static enum { balloonHelpIdle , balloonHelpWait, balloonHelpShow } balloonHelpState = balloonHelpIdle; +static HWND balloonHelpHWnd = (HWND)0; +static int balloonHelpFontSize = 8; +static char balloonHelpFaceName[] = "MS Sans Serif"; +static HFONT balloonHelpOldFont; +static HFONT balloonHelpNewFont; +static int balloonHelpEnable = TRUE; +static wControl_p balloonControlButton = NULL; + +static BOOL_T helpInitted = FALSE; +static DWORD dwCookie; + +#define CONTROL_BASE (1) +typedef struct { + wControl_p b; + } controlMap_t; +dynArr_t controlMap_da; +#define controlMap(N) DYNARR_N(controlMap_t,controlMap_da,N) + + +static char * appName; +static char * helpFile; +char *mswProfileFile; + +static wBalloonHelp_t * balloonHelpStrings; + +static wCursor_t curCursor = wCursorNormal; + +#ifdef HELPSTR +static FILE * helpStrF; +#endif +static int inMainWndProc = FALSE; + +int newHelp = 1; + +static wBool_t mswWinBlockEnabled = TRUE; + +static FILE * dumpControlsF; +static int dumpControls; + +extern char *userLocale; + + +/* + ***************************************************************************** + * + * Internal Utility functions + * + ***************************************************************************** + */ + + +DWORD GetTextExtent( + HDC hDc, + CHAR * str, + UINT len ) +{ + SIZE size; + GetTextExtentPoint( hDc, str, len, &size ); + return size.cx + (size.cy<<16); +} + + +static char * controlNames[] = { + "MAIN", "POPUP", + "BUTTON", "STRING", "INTEGER", "FLOAT", + "LIST", "DROPLIST", "COMBOLIST", + "RADIO", "TOGGLE", + "DRAW", "TEXT", "MESSAGE", "LINES", + "MENUITEM", "CHOICEITEM", "BOX" }; + +static void doDumpControls(void) +{ + wControl_p b; + int inx; + if ( !dumpControls ) + return; + if ( !dumpControlsF ) { + dumpControlsF = fopen( "controls.lst", "w" ); + if ( !dumpControlsF ) + abort(); + } + for ( inx=0; inx<controlMap_da.cnt-1; inx++ ) { + b = controlMap(inx).b; + if ( b ) { + fprintf( dumpControlsF, "[%0.3d] [%x] %s %s %s\n", inx, + b->hWnd, + (b->type>=0&&b->type<=B_BOX?controlNames[b->type]:"NOTYPE"), + (b->labelStr?b->labelStr:"<NULL>"), + (b->helpStr?b->helpStr:"<NULL>") ); + } else { + fprintf( dumpControlsF, "[%0.3d] <NULL>\n", inx ); + } + } + fflush( dumpControlsF ); + fclose( dumpControlsF ); + dumpControls = 0; +} + +void mswFail( const char * where ) +{ + sprintf( mswTmpBuff, "%s\n# Controls %d", where, controlMap_da.cnt ); + MessageBox( NULL, mswTmpBuff, "FAIL", MB_TASKMODAL|MB_OK ); + doDumpControls(); +} +/* +static UINT curSysRes = 100; +static UINT curGdiRes = 100; +static UINT curUsrRes = 100; +static UINT curMinRes = 100; +*/ + +wControl_p mswMapIndex( INDEX_T inx ) +{ + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) { + mswFail("mswMapIndex- bad index"); + exit(1); + } + return controlMap(inx-CONTROL_BASE).b; +} + + +void mswRepaintLabel( HWND hWnd, wControl_p b ) +{ + HDC hDc; + HBRUSH oldBrush, newBrush; + RECT rect; + DWORD dw; + LABELFONTDECL + + + if (b->labelStr) { + hDc = GetDC( hWnd ); + LABELFONTSELECT + newBrush = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) ); + oldBrush = SelectObject( hDc, newBrush ); + dw = GetTextExtent( hDc, CAST_AWAY_CONST b->labelStr, strlen(b->labelStr) ); + rect.left = b->labelX; + rect.top = b->labelY; + rect.right = b->labelX + LOWORD(dw); + rect.bottom = b->labelY + HIWORD(dw); + FillRect( hDc, &rect, newBrush ); + DeleteObject( SelectObject( hDc, oldBrush ) ); + /*SetBkMode( hDc, OPAQUE );*/ + SetBkColor( hDc, GetSysColor( COLOR_BTNFACE ) ); + if (!TextOut( hDc, b->labelX, b->labelY, b->labelStr, strlen(b->labelStr) ) ) + mswFail( "Repainting text label" ); + LABELFONTRESET + ReleaseDC( hWnd, hDc ); + } +} + + + +int mswRegister( + wControl_p w ) +{ + int index; + DYNARR_APPEND( controlMap_t, controlMap_da, 25 ); + index = controlMap_da.cnt-1+CONTROL_BASE; + controlMap(controlMap_da.cnt-1).b = (wControl_p)w; + return index; +} + + +void mswUnregister( + int index ) +{ + if (index < 0 || index > controlMap_da.cnt) { + mswFail("mswMapIndex- bad index"); + exit(1); + } + controlMap(index-CONTROL_BASE).b = NULL; +} + +void * mswAlloc( + wWin_p parent, + wType_e type, + const char * labelStr, + int size, + void * data, + int * index ) +{ + wControl_p w = (wControl_p)calloc( 1, size ); + + if (w == NULL) + abort(); + *index = mswRegister( w ); + w->type = type; + w->next = NULL; + w->parent = parent; + w->x = 0; + w->y = 0; + w->w = 0; + w->h = 0; + w->option = 0; + w->labelX = w->labelY = 0; + w->labelStr = labelStr; + w->helpStr = NULL; + w->hWnd = (HWND)0; + w->data = data; + w->focusChainNext = NULL; + w->shown = TRUE; + return w; +} + + +void mswComputePos( + wControl_p b, + wPos_t origX, + wPos_t origY ) +{ + wWin_p w = b->parent; + + if (origX >= 0) + b->x = origX; + else + b->x = w->lastX + (-origX) - 1; + if (origY >= 0) + b->y = origY; + else + b->y = w->lastY + (-origY) - 1; + + b->labelX = b->x; + b->labelY = b->y+2; + + if (b->labelStr) { + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( w->hWnd ); + LABELFONTSELECT + lab_l = strlen(b->labelStr); + dw = GetTextExtent( hDc, CAST_AWAY_CONST b->labelStr, lab_l ); + b->labelX -= LOWORD(dw) + 5; + LABELFONTRESET + ReleaseDC( w->hWnd, hDc ); + } +} + +void mswAddButton( + wControl_p b, + BOOL_T paintLabel, + const char * helpStr ) +{ + wWin_p w = b->parent; + BOOL_T resize = FALSE; + RECT rect; + + if (w->first == NULL) { + w->first = b; + } else { + w->last->next = b; + } + w->last = b; + b->next = NULL; + b->parent = w; + w->lastX = b->x + b->w; + w->lastY = b->y + b->h; + if ((w->option&F_AUTOSIZE)!=0 && w->lastX > w->w) { + w->w = w->lastX; + resize = TRUE; + } + if ((w->option&F_AUTOSIZE)!=0 && w->lastY > w->h) { + w->h = w->lastY; + resize = TRUE; + } + + if (resize) { + w->busy = TRUE; + rect.left = 0; + rect.top = 0; + rect.right = w->w+w->padX; + rect.bottom = w->h+w->padY; + AdjustWindowRect( &rect, w->style, (w->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + if (!SetWindowPos( w->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + SWP_NOMOVE)) + mswFail("SetWindowPos"); + w->busy = FALSE; + } + + if (paintLabel) + mswRepaintLabel( w->hWnd, (wControl_p)b ); + + if (helpStr == NULL) + return; + b->helpStr = mswStrdup( helpStr ); + +#ifdef HELPSTR + if (helpStrF) + fprintf( helpStrF, "HELPSTR - %s\n", helpStr?helpStr:"<>" ); +#endif +} + + +void mswResize( + wWin_p w ) +{ + wControl_p b; + RECT rect; + + w->lastX = 0; + w->lastY = 0; + for (b=w->first; b; b=b->next) { + if (w->lastX < (b->x + b->w)) + w->lastX = b->x + b->w; + if (w->lastY < (b->y + b->h)) + w->lastY = b->y + b->h; + } + + if (w->option&F_AUTOSIZE) { + w->w = w->lastX; + w->h = w->lastY; + w->busy = TRUE; + rect.left = 0; + rect.top = 0; + rect.right = w->w + w->padX; + rect.bottom = w->h + w->padY; + AdjustWindowRect( &rect, w->style, (w->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + if (!SetWindowPos( w->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + SWP_NOMOVE|SWP_NOZORDER)) + mswFail("SetWindowPos"); + w->busy = FALSE; + } +} + + + +void mswChainFocus( + wControl_p b ) +{ + wWin_p w; + w = b->parent; + if (w->option&F_NOTAB) + return; + if (b->option&BO_NOTAB) + return; + if (w->focusChainFirst == NULL) { + w->focusChainFirst = w->focusChainLast = w->focusChainNext = b; + b->focusChainNext = b; + } else { + w->focusChainLast->focusChainNext = b; + w->focusChainLast = b; + b->focusChainNext = w->focusChainFirst; + } +} + +void mswSetFocus( + wControl_p b ) +{ + if (b && b->type != B_MENUITEM && b->focusChainNext) + b->parent->focusChainNext = b; +} + +/* + ****************************************************************************** + * + * Main and Popup Windows + * + ****************************************************************************** + */ + +static void getSavedSizeAndPos( + long option, + const char * nameStr, + wPos_t *rw, + wPos_t *rh, + wPos_t *rx, + wPos_t *ry, + int *showCmd ) +{ + int x, y, w, h; + const char *cp; + char *cq; + int state; + + *showCmd = SW_SHOWNORMAL; + + if ( (option&F_RECALLPOS) && nameStr ) { + if ( (option & F_RESIZE) && + (cp = wPrefGetString( "msw window size", nameStr)) && + (state = (int)strtol( cp, &cq, 10 ), cp != cq) && + (cp = cq, w = (wPos_t)strtod( cp, &cq ), cp != cq ) && + (cp = cq, h = (int)strtod( cp, &cq ), cp != cq) + ) { + if (state == 1) + *showCmd = SW_SHOWMINIMIZED; + else if (state == 2) + *showCmd = SW_SHOWMAXIMIZED; + if (w < 10) + w = 10; + if (h < 10) + h = 10; + if (w > screenWidth) + w = screenWidth; + if (h > screenHeight) + h = screenHeight; + *rw = w; + *rh = h; + } + + if ((cp = wPrefGetString( "msw window pos", nameStr)) && + (x = (wPos_t)strtod( cp, &cq ), cp != cq) && + (cp = cq, y = (wPos_t)strtod( cp, &cq ), cp != cq) + ) { + if (y < 0) + y = 0; + if (x < 0) + x = 0; + if ( y > screenHeight-40 ) + y = screenHeight-40; + if ( x > screenWidth-40 ) + x = screenWidth-40; + *rx = x; + *ry = y; + } + } +} + + +static wWin_p winCommonCreate( + HWND hWnd, + int typ, + long option, + const char * className, + long style, + const char * labelStr, + wWinCallBack_p winProc, + wPos_t w, + wPos_t h, + void * data, + const char * nameStr, + int * showCmd ) +{ + wWin_p win; + int index; + wPos_t ww, hh, xx, yy; + RECT rect; + + win = (wWin_p)mswAlloc( NULL, typ, mswStrdup(labelStr), sizeof *win, data, &index ); + win->option = option; + win->first = win->last = NULL; + win->lastX = 0; + win->lastY = 0; + win->winProc = winProc; + win->centerWin = TRUE; + win->modalLevel = 0; +#ifdef OWNERICON + win->wicon_bm = (HBITMAP)0; +#endif + win->busy = TRUE; + ww = hh = xx = yy = CW_USEDEFAULT; + getSavedSizeAndPos( option, nameStr, &ww, &hh, &xx, &yy, showCmd ); + if (xx != CW_USEDEFAULT) + win->centerWin = FALSE; + if (option & F_RESIZE) { + style |= WS_THICKFRAME; + if ( ww != CW_USEDEFAULT ) { + w = ww; + h = hh; + option &= ~F_AUTOSIZE; + win->option = option; + } + } + + if ( option & F_AUTOSIZE ) { + win->padX = w; + win->padY = h; + } else { + win->padX = 0; + win->padY = 0; + win->w = w; + win->h = h; + } + win->style = style; + rect.left = 0; + rect.top = 0; + rect.right = win->w + win->padX; + rect.bottom = win->h + win->padY; + AdjustWindowRect( &rect, win->style, (win->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + win->hWnd = CreateWindow( className, labelStr, style, + xx, yy, + rect.right-rect.left, rect.bottom-rect.top, + hWnd, NULL, + mswHInst, NULL ); + if (win->hWnd == (HWND)0) { + mswFail( "CreateWindow(POPUP)" ); + } else { + SetWindowWord( win->hWnd, 0, (WORD)index ); + } + win->baseStyle = WS_GROUP; + win->focusChainFirst = win->focusChainLast = win->focusChainNext = NULL; + if (winFirst == NULL) { + winFirst = winLast = win; + } else { + winLast->next = (wControl_p)win; + winLast = win; + } +#ifdef HELPSTR + if (helpStrF) + fprintf( helpStrF, "WINDOW - %s\n", labelStr ); +#endif + win->nameStr = mswStrdup( nameStr ); + if (typ == W_MAIN) + mswInitColorPalette(); +#ifdef LATER + hDc = GetDC( win->hWnd ); + oldHPal = SelectPalette( hDc, mswPalette, 0 ); + ReleaseDC( win->hWnd, hDc ); +#endif + return win; +} + +void wInitAppName(char *_appName) +{ + appName = (char *)malloc( strlen(_appName) + 1 ); + strcpy(appName, _appName); +} + + +/** + * Initialize the application's main window. This function does the necessary initialization + * of the application including creation of the main window. + * + * \param name IN internal name of the application. Used for filenames etc. + * \param x IN size + * \param y IN size + * \param helpStr IN ?? + * \param labelStr IN window title + * \param nameStr IN ?? + * \param option IN options for window creation + * \param winProc IN pointer to main window procedure + * \param data IN ?? + * \return window handle or NULL on error + */ + +wWin_p wWinMainCreate( + const char * name, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + const char * nameStr, + long option, + wWinCallBack_p winProc, + void * data ) +{ + wWin_p w; + RECT rect; + const char * appDir; + const char * libDir; + int showCmd; + int error; + HDC hDc; + TEXTMETRIC tm; + char *pos; + char * configName; + + /* check for configuration name */ + if( pos = strchr( name, ';' )) { + /* if found, split application name and configuration name */ + configName = (char *)malloc( strlen( name ) + 1 ); + strcpy( configName, pos + 1 ); + } else { + /* if not found, application name and configuration name are same */ + configName = (char*)malloc( strlen(name)+1 ); + strcpy( configName, name ); + } + + appDir = wGetAppWorkDir(); + if ( appDir == NULL ) { + free( configName ); + return NULL; + } + mswProfileFile = (char*)malloc( strlen(appDir)+1+strlen(configName)+1+3+1 ); + wsprintf( mswProfileFile, "%s\\%s.ini", appDir, configName ); + free( configName ); + + error = WritePrivateProfileString( "mswtest", "test", "ok", mswProfileFile ); + if ( error <= 0 ) { + sprintf( mswTmpBuff, "Can not write to %s.\nPlease make sure the directory exists and is writable", mswProfileFile ); + wNoticeEx( NT_ERROR, mswTmpBuff, "Ok", NULL ); + return NULL; + } + libDir = wGetAppLibDir(); + /* length of path + \ + length of filename + . + length of extension + \0 */ + helpFile = (char*)malloc( strlen(libDir) + 1 + strlen(appName) + 1 + 3 + 1 ); + wsprintf( helpFile, "%s\\%s.chm", libDir, appName ); + + wPrefGetInteger( "msw tweak", "ThickFont", &mswThickFont, 0 ); + + showCmd = SW_SHOW; + w = winCommonCreate( NULL, W_MAIN, option|F_RESIZE, "MswMainWindow", + WS_OVERLAPPEDWINDOW, labelStr, winProc, x, y, data, + nameStr, &showCmd ); + mswHWnd = w->hWnd; + if ( !mswThickFont ) { + DWORD dw; + SendMessage( w->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + hDc = GetDC( w->hWnd ); + GetTextMetrics( hDc, &tm ); + mswEditHeight = tm.tmHeight+2; + dw = GetTextExtent( hDc, "AXqypj", 6 ); + mswEditHeight = HIWORD(dw)+2; + ReleaseDC( w->hWnd, hDc ); + } + ShowWindow( w->hWnd, showCmd ); + UpdateWindow( w->hWnd ); + GetWindowRect( w->hWnd, &rect ); + GetClientRect( w->hWnd, &rect ); + w->busy = FALSE; + + + return w; +} + +wWin_p wWinPopupCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + const char * nameStr, + long option, + wWinCallBack_p winProc, + void * data ) +{ + wWin_p w; + DWORD style; + HMENU sysMenu; + int showCmd; + static DWORD overlapped = WS_OVERLAPPED; + static DWORD popup = WS_POPUP; + + style = popup; + style |= WS_BORDER | WS_CAPTION | WS_SYSMENU; + w = winCommonCreate( parent?parent->hWnd:mswHWnd, W_POPUP, option, + "MswPopUpWindow", + style, labelStr, winProc, x, y, data, nameStr, &showCmd ); + + w->helpStr = mswStrdup( helpStr ); + + sysMenu = GetSystemMenu( w->hWnd, FALSE ); + if (sysMenu) { + DeleteMenu( sysMenu, SC_RESTORE, MF_BYCOMMAND ); + /*DeleteMenu( sysMenu, SC_MOVE, MF_BYCOMMAND );*/ + /*DeleteMenu( sysMenu, SC_SIZE, MF_BYCOMMAND );*/ + DeleteMenu( sysMenu, SC_MINIMIZE, MF_BYCOMMAND ); + DeleteMenu( sysMenu, SC_MAXIMIZE, MF_BYCOMMAND ); + DeleteMenu( sysMenu, SC_TASKLIST, MF_BYCOMMAND ); + DeleteMenu( sysMenu, 4, MF_BYPOSITION ); + } + w->busy = FALSE; + return w; +} + +void wWinSetBigIcon( + wWin_p win, + wIcon_p bm ) +{ +#ifdef OWNERICON + win->wicon_w = bm->w; + win->wicon_h = bm->h; + win->wicon_bm = mswCreateBitMap( + GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), RGB( 255, 255, 255 ), + bm->w, bm->h, bm->bits ); +#endif +} + + +void wWinSetSmallIcon( + wWin_p win, + wIcon_p bm ) +{ +#ifdef OWNERICON + win->wicon_w = bm->w; + win->wicon_h = bm->h; + win->wicon_bm = mswCreateBitMap( + GetSysColor(COLOR_BTNTEXT), RGB( 255, 255, 255 ), RGB( 255, 255, 255 ), + bm->w, bm->h, bm->bits ); +#endif +} + + +void wWinTop( + wWin_p win ) +{ + /*BringWindowToTop( win->hWnd );*/ + SetWindowPos( win->hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE ); + SetFocus( win->hWnd ); +} + + +DWORD mswGetBaseStyle( wWin_p win ) +{ + DWORD style; + style = win->baseStyle; + win->baseStyle = 0; + return style; +} + + +static wAccelKey_e translateExtKey( UINT wParam ) +{ + wAccelKey_e extChar; + extChar = wAccelKey_None; + switch( wParam ) { + case VK_DELETE: extChar = wAccelKey_Del; break; + case VK_INSERT: extChar = wAccelKey_Ins; break; + case VK_HOME: extChar = wAccelKey_Home; break; + case VK_END: extChar = wAccelKey_End; break; + case VK_PRIOR: extChar = wAccelKey_Pgup; break; + case VK_NEXT: extChar = wAccelKey_Pgdn; break; + case VK_UP: extChar = wAccelKey_Up; break; + case VK_DOWN: extChar = wAccelKey_Down; break; + case VK_RIGHT: extChar = wAccelKey_Right; break; + case VK_LEFT: extChar = wAccelKey_Left; break; + case VK_BACK: extChar = wAccelKey_Back; break; + /*case VK_F1: extChar = wAccelKey_F1; break;*/ + case VK_F2: extChar = wAccelKey_F2; break; + case VK_F3: extChar = wAccelKey_F3; break; + case VK_F4: extChar = wAccelKey_F4; break; + case VK_F5: extChar = wAccelKey_F5; break; + case VK_F6: extChar = wAccelKey_F6; break; + case VK_F7: extChar = wAccelKey_F7; break; + case VK_F8: extChar = wAccelKey_F8; break; + case VK_F9: extChar = wAccelKey_F9; break; + case VK_F10: extChar = wAccelKey_F10; break; + case VK_F11: extChar = wAccelKey_F11; break; + case VK_F12: extChar = wAccelKey_F12; break; + } + return extChar; +} + + +long notModKey; +int mswTranslateAccelerator( + HWND hWnd, + LPMSG pMsg ) +{ + long acclKey; + long state; + wWin_p win; + wControl_p b; + + if ( pMsg->message != WM_KEYDOWN ) + return FALSE; + acclKey = pMsg->wParam; + b = getControlFromCursor( pMsg->hwnd, &win ); + if ( win == NULL ) + return 0; + if ( b != NULL ) { + switch (b->type) { + case B_STRING: + case B_INTEGER: + case B_FLOAT: + case B_LIST: + case B_DROPLIST: + case B_COMBOLIST: + case B_TEXT: + return 0; + } + } + if ( acclKey == (long)VK_F1 ) { + closeBalloonHelp(); + if (!b && win) { + wHelp( win->helpStr ); + } else { + if (b->helpStr) + wHelp( b->helpStr ); + else if (b->parent) + wHelp( b->parent->nameStr ); + } + return 1; + } + /*acclKey = translateExtKey( (WORD)acclKey );*/ + state = 0; + if ( GetKeyState(VK_CONTROL) & 0x1000 ) + state |= WKEY_CTRL; + if ( GetKeyState(VK_MENU) & 0x1000 ) + state |= WKEY_ALT; + if ( GetKeyState(VK_SHIFT) & 0x1000 ) + state |= WKEY_SHIFT; + state <<= 8; + acclKey |= state; + if (pMsg->wParam > 0x12) + notModKey = TRUE; + return mswMenuAccelerator( win, acclKey ); +} + +/* + ****************************************************************************** + * + * Window Utilities + * + ****************************************************************************** + */ + + + +void wGetDisplaySize( POS_T * width, POS_T * height ) +{ + *width = screenWidth; + *height = screenHeight; +} + + +void wWinGetSize( wWin_p w, POS_T * width, POS_T * height ) +{ + RECT rect; + GetWindowRect( w->hWnd, &rect ); + GetClientRect( w->hWnd, &rect ); + w->w = rect.right - rect.left; + w->h = rect.bottom - rect.top; + *width = w->w; + *height = w->h; +} + + +void wWinSetSize( wWin_p w, POS_T width, POS_T height ) +{ + RECT rect; + w->w = width; + w->h = height; + rect.left = 0; + rect.top = 0; + rect.right = w->w /*+w->padX*/; + rect.bottom = w->h /*+w->padY*/; + AdjustWindowRect( &rect, w->style, (w->option&F_MENUBAR)?1:0 ); + rect.bottom += mFixBorderH; + if (!SetWindowPos( w->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + SWP_NOMOVE|SWP_NOZORDER)) + mswFail("wWinSetSize"); + InvalidateRect( w->hWnd, NULL, TRUE ); +} + + +static int blocking; +static void blockingLoop( void ) +{ + MSG msg; + int myBlocking=blocking; + while (blocking>=myBlocking && GetMessage( &msg, NULL, 0, 0 )) { + if ( +#ifdef DOTRANSACCEL + (!TranslateAccelerator( mswWin->hWnd, hMswAccel, &msg )) && +#endif + (!mswTranslateAccelerator( mswWin->hWnd, &msg )) ) { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } +} + + +static void savePos( wWin_p win ) +{ + char posStr[20]; + WINDOWPLACEMENT windowPlace; + wPos_t w, h; + RECT rect; + + if ( win->nameStr && + IsWindowVisible( win->hWnd) /*&& !IsIconic( win->hWnd )*/ ) { + windowPlace.length = sizeof windowPlace; + GetWindowPlacement( win->hWnd, &windowPlace ); + if (win->option&F_RECALLPOS) { + wsprintf( posStr, "%d %d", + windowPlace.rcNormalPosition.left, + windowPlace.rcNormalPosition.top ); + wPrefSetString( "msw window pos", win->nameStr, posStr ); + if (win->option&F_RESIZE) { + GetClientRect( win->hWnd, &rect ); + w = rect.right - rect.left; + h = rect.bottom - rect.top; + w = windowPlace.rcNormalPosition.right - windowPlace.rcNormalPosition.left; + h = windowPlace.rcNormalPosition.bottom - windowPlace.rcNormalPosition.top; + w -= mResizeBorderW*2; + h -= mResizeBorderH*2 + mTitleH; + if (win->option&F_MENUBAR) + h -= mMenuH; + wsprintf( posStr, "%d %d %d", + ( windowPlace.showCmd == SW_SHOWMINIMIZED ? 1 : + (windowPlace.showCmd == SW_SHOWMAXIMIZED ? 2 : 0 ) ), + w, h ); + wPrefSetString( "msw window size", win->nameStr, posStr ); + } + } + } +} + + +void wWinShow( + wWin_p win, + BOOL_T show ) +{ + wPos_t x, y; + wWin_p win1; + + win->busy = TRUE; + if (show) { + if (win->centerWin) { + x = (screenWidth-win->w)/2; + y = (screenHeight-win->h)/2; + if (x<0) + y = 0; + if (x<0) + y = 0; + if (!SetWindowPos( win->hWnd, HWND_TOP, x, y, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail( "wWinShow:SetWindowPos()" ); + } + win->centerWin = FALSE; + win->shown = TRUE; + if (mswHWnd == (HWND)0 || !IsIconic(mswHWnd) ) { + ShowWindow( win->hWnd, SW_SHOW ); + if (win->focusChainFirst) { + SetFocus( win->focusChainFirst->hWnd ); + } + win->pendingShow = FALSE; + if ( mswWinBlockEnabled && (win->option & F_BLOCK) ) { + blocking++; + inMainWndProc = FALSE; + for ( win1 = winFirst; win1; win1=(wWin_p)win1->next ) { + if ( win1->shown && win1 != win ) { + if (win1->modalLevel == 0 ) + EnableWindow( win1->hWnd, FALSE ); + win1->modalLevel++; + } + } + win->busy = FALSE; + blockingLoop(); + } + } else { + win->pendingShow = TRUE; + needToDoPendingShow = TRUE; + } + } else { + savePos( win ); + ShowWindow( win->hWnd, SW_HIDE ); + /*SetWindowPos( win->hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_HIDEWINDOW );*/ + if ( mswWinBlockEnabled && (win->option & F_BLOCK) ) { + blocking--; + for ( win1 = winFirst; win1; win1=(wWin_p)win1->next ) { + if ( win1->shown && win1 != win ) { + if ( win1->modalLevel > 0 ) + win1->modalLevel--; + if (win1->modalLevel == 0 ) + EnableWindow( win1->hWnd, TRUE ); + } + } + } + savePos( win ); + win->pendingShow = FALSE; + win->shown = FALSE; + } + win->busy = FALSE; +} + + +void wWinBlockEnable( + wBool_t enabled ) +{ + mswWinBlockEnabled = enabled; +} + + +wBool_t wWinIsVisible( + wWin_p w ) +{ + return IsWindowVisible(w->hWnd); +} + + +void wWinSetTitle( + wWin_p w, + const char * title ) +{ + SetWindowText( w->hWnd, title ); +} + + +void wWinSetBusy( + wWin_p w, + BOOL_T busy ) +{ + HMENU menuH; + UINT uEnable; + int cnt, inx; + wControl_p b; + + w->isBusy = busy; + menuH = GetMenu( w->hWnd ); + if (menuH) { + uEnable = MF_BYPOSITION|(busy?MF_DISABLED:MF_ENABLED); + cnt = GetMenuItemCount(menuH); + for (inx=0; inx<cnt; inx++) + EnableMenuItem( menuH, inx, uEnable ); + } + for (b=w->first; b; b=b->next) { + if ( (b->option&BO_DISABLED)==0) { + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->setBusyProc) { + mswCallBacks[b->type]->setBusyProc( b, busy ); + } else { + if (b->hWnd) + EnableWindow( b->hWnd, (BOOL)!busy ); + } + } + } +} + + +const char * wWinGetTitle( + wWin_p w ) +{ + return w->labelStr; +} + + +void wWinClear( + wWin_p win, + wPos_t x, + wPos_t y, + wPos_t width, + wPos_t height ) +{ +} + +void wSetCursor( + wCursor_t cursor ) +{ + switch ( cursor ) { + case wCursorNormal: + case wCursorQuestion: + default: + SetCursor( LoadCursor( NULL, IDC_ARROW ) ); + break; + case wCursorWait: + SetCursor( LoadCursor( NULL, IDC_WAIT ) ); + break; + case wCursorCross: + SetCursor( LoadCursor( NULL, IDC_CROSS ) ); + break; + case wCursorIBeam: + SetCursor( LoadCursor( NULL, IDC_IBEAM ) ); + break; + } + curCursor = cursor; +} + +void wWinDoCancel( wWin_p win ) +{ + wControl_p b; + for (b=win->first; b; b=b->next) { + if ((b->type == B_BUTTON) && (b->option & BB_CANCEL) ) { + mswButtPush( b ); + } + } +} + +unsigned long wGetTimer( void ) +{ + return (unsigned long)GetTickCount(); +} + + +/* + ****************************************************************************** + * + * Control Utilities + * + ****************************************************************************** + */ + + + +void wControlSetHelp( + wControl_p b, + const char * help ) +{ + if (b->helpStr) + free(CAST_AWAY_CONST b->helpStr); + if (help) + b->helpStr = mswStrdup( help ); + else + b->helpStr = NULL; +} + + +/** + * Add control to circular list of synonymous controls. Synonymous controls are kept in sync by + * calling wControlLinkedActive for one member of the list + * + * \param IN first control + * \param IN second control + * \return none + */ + +void wControlLinkedSet( wControl_p b1, wControl_p b2 ) +{ + b2->synonym = b1->synonym; + if( b2->synonym == NULL ) + b2->synonym = b1; + + b1->synonym = b2; +} + +/** + * Activate/deactivate a group of synonymous controls. + * + * \param IN control + * \param IN state + * \return none + */ + +void wControlLinkedActive( wControl_p b, int active ) +{ + wControl_p savePtr = b; + + if( savePtr->type == B_MENUITEM ) + wMenuPushEnable( (wMenuPush_p)savePtr, active ); + else + wControlActive( savePtr, active ); + + savePtr = savePtr->synonym; + + while( savePtr && savePtr != b ) { + + if( savePtr->type == B_MENUITEM ) + wMenuPushEnable( (wMenuPush_p)savePtr, active ); + else + wControlActive( savePtr, active ); + + savePtr = savePtr->synonym; + } +} + +void wControlShow( wControl_p b, BOOL_T show ) +{ + RECT rc; + if (show) { + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->repaintProc) + mswCallBacks[b->type]->repaintProc( b->parent->hWnd, b ); + } else { + if( b->labelStr ) { + rc.left = b->labelX; + rc.right = b->x; + rc.top = b->labelY; + rc.bottom = b->labelY+b->h; + InvalidateRect( ((wControl_p)b->parent)->hWnd, &rc, TRUE ); + } + } + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->showProc) { + mswCallBacks[b->type]->showProc( b, show ); + } else { + ShowWindow( b->hWnd, show?SW_SHOW:SW_HIDE ); +#ifdef SHOW_DOES_SETFOCUS + if (show && (b->option&BO_READONLY)==0 && b->hWnd != GetFocus() ) { + hWnd = SetFocus( b->hWnd ); + } +#endif + } + b->shown = show; +} + + +void wControlSetFocus( + wControl_p b ) +{ + if ( b->hWnd ) + SetFocus( b->hWnd ); +} + + +void wControlActive( + wControl_p b, + int active ) +{ + if (active) + b->option &= ~BO_DISABLED; + else + b->option |= BO_DISABLED; + if (b->parent->isBusy) + return; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->setBusyProc) { + mswCallBacks[b->type]->setBusyProc( b, !active ); + } else { + EnableWindow( b->hWnd, (BOOL)active ); + InvalidateRect( b->hWnd, NULL, TRUE ); + } +} + + +const char * wControlGetHelp( wControl_p b ) +{ + return b->helpStr; +} + + +wPos_t wLabelWidth( const char * labelStr ) +{ + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( mswHWnd ); + lab_l = strlen(labelStr); + LABELFONTSELECT + dw = GetTextExtent( hDc, CAST_AWAY_CONST labelStr, lab_l ); + LABELFONTRESET + ReleaseDC( mswHWnd, hDc ); + return LOWORD(dw) + 5; +} + + +wPos_t wControlGetWidth( + wControl_p b) /* Control */ +{ + return b->w; +} + + +wPos_t wControlGetHeight( + wControl_p b) /* Control */ +{ + return b->h; +} + + +wPos_t wControlGetPosX( + wControl_p b) /* Control */ +{ + return b->x; +} + + +wPos_t wControlGetPosY( + wControl_p b) /* Control */ +{ + return b->y; +} + + +void wControlSetPos( + wControl_p b, + wPos_t x, + wPos_t y ) +{ + b->labelX = x; + b->labelY = y+2; + + if (b->labelStr) { + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( b->parent->hWnd ); + LABELFONTSELECT + lab_l = strlen(b->labelStr); + dw = GetTextExtent( hDc, CAST_AWAY_CONST b->labelStr, lab_l ); + b->labelX -= LOWORD(dw) + 5; + LABELFONTRESET + ReleaseDC( b->parent->hWnd, hDc ); + } + + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->setPosProc) { + mswCallBacks[b->type]->setPosProc( b, x, y ); + } else { + b->x = x; + b->y = y; + if (b->hWnd) + if (!SetWindowPos( b->hWnd, HWND_TOP, x, y, + CW_USEDEFAULT, CW_USEDEFAULT, + SWP_NOSIZE|SWP_NOZORDER)) + mswFail("wControlSetPos"); + } +} + + +void wControlSetLabel( + wControl_p b, + const char * labelStr ) +{ + if ( b->type == B_RADIO || b->type == B_TOGGLE ) { + ; + } else { + int lab_l; + HDC hDc; + DWORD dw; + LABELFONTDECL + + hDc = GetDC( b->parent->hWnd ); + lab_l = strlen(labelStr); + LABELFONTSELECT + dw = GetTextExtent( hDc, CAST_AWAY_CONST labelStr, lab_l ); + LABELFONTRESET + b->labelX = b->x - LOWORD(dw) - 5; + ReleaseDC( b->parent->hWnd, hDc ); + b->labelStr = mswStrdup( labelStr ); + if (b->type == B_BUTTON) + SetWindowText( b->hWnd, labelStr ); + } +} + + +void wControlSetContext( + wControl_p b, + void * context ) +{ + b->data = context; +} + +static int controlHiliteWidth = 5; +static int controlHiliteWidth2 = 3; +void wControlHilite( + wControl_p b, + wBool_t hilite ) +{ + HDC hDc; + HPEN oldPen, newPen; + int oldMode; + + if ( b == NULL ) return; + if ( !IsWindowVisible(b->parent->hWnd) ) return; + if ( !IsWindowVisible(b->hWnd) ) return; + hDc = GetDC( b->parent->hWnd ); + newPen = CreatePen( PS_SOLID, controlHiliteWidth, RGB(0,0,0) ); + oldPen = SelectObject( hDc, newPen ); + oldMode = SetROP2( hDc, R2_NOTXORPEN ); + MoveTo( hDc, b->x-controlHiliteWidth2, b->y-controlHiliteWidth2 ); + LineTo( hDc, b->x+b->w+controlHiliteWidth2, b->y-controlHiliteWidth2 ); + LineTo( hDc, b->x+b->w+controlHiliteWidth2, b->y+b->h+controlHiliteWidth2 ); + LineTo( hDc, b->x-controlHiliteWidth2, b->y+b->h+controlHiliteWidth2 ); + LineTo( hDc, b->x-controlHiliteWidth2, b->y-controlHiliteWidth2 ); + SetROP2( hDc, oldMode ); + SelectObject( hDc, oldPen ); + DeleteObject( newPen ); + ReleaseDC( b->parent->hWnd, hDc ); +} + +/* + ***************************************************************************** + * + * Exported Utility Functions + * + ***************************************************************************** + */ + + +void wMessage( + wWin_p w, + const char * msg, + int beep ) +{ + HDC hDc; + int oldRop; + POS_T h; + RECT rect; + LABELFONTDECL + + if (beep) + MessageBeep(0); + GetClientRect( w->hWnd, &rect ); + hDc = GetDC( w->hWnd ); + oldRop = SetROP2( hDc, R2_WHITE ); + h = w->h+2; + Rectangle( hDc, 0, h, w->w, h ); + SetROP2( hDc, oldRop ); + LABELFONTSELECT + TextOut( hDc, 0, h, msg, strlen(msg) ); + LABELFONTRESET + ReleaseDC( w->hWnd, hDc ); +} + + +void wExit( int rc ) +{ + INDEX_T inx; + wControl_p b; + + mswPutCustomColors(); + wPrefFlush(); + for ( inx=controlMap_da.cnt-1; inx>=0; inx-- ) { + b = controlMap(inx).b; + if (b != NULL) { + if (b->type == W_MAIN || b->type == W_POPUP) { + wWin_p w = (wWin_p)b; + savePos( w ); + if (w->winProc != NULL) + w->winProc( w, wQuit_e, w->data ); + } + } + } + for ( inx=controlMap_da.cnt-1; inx>=0; inx-- ) { + b = controlMap(inx).b; + if (b != NULL) { + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->doneProc != NULL) + mswCallBacks[b->type]->doneProc( b ); + } + controlMap(inx).b = NULL; + } + deleteBitmaps(); + if (mswOldTextFont != (HFONT)0) + DeleteObject( mswOldTextFont ); + if (helpInitted) { + WinHelp(mswHWnd, helpFile, HELP_QUIT, 0L ); + helpInitted = FALSE; + } + if (balloonHelpHWnd) { + HDC hDc; + hDc = GetDC( balloonHelpHWnd ); + SelectObject( hDc, balloonHelpOldFont ); + DeleteObject( balloonHelpNewFont ); + ReleaseDC( balloonHelpHWnd, hDc ); + } +#ifdef HELPSTR + fclose( helpStrF ); +#endif + DestroyWindow( mswHWnd ); + if (mswPalette) { + DeleteObject( mswPalette ); + /*DeleteObject( mswPrintPalette );*/ + } +} + + +void wFlush( + void ) +{ + wWin_p win; + + inMainWndProc = FALSE; + mswRepaintAll(); + for (win=winFirst; win; win=(wWin_p)win->next) + UpdateWindow( win->hWnd ); +} + +void wUpdate( + wWin_p win ) +{ + UpdateWindow( win->hWnd ); +} + +static wBool_t paused; +static wAlarmCallBack_p alarmFunc; +static setTriggerCallback_p triggerFunc; +static wControl_p triggerControl; + +/** + * Wait until the pause timer expires. During that time, the message loop is + * handled and queued messages are processed + */ + +static void pausedLoop( void ) +{ + MSG msg; + while (paused && GetMessage( &msg, NULL, 0, 0 )) { + if ( (mswWin) && (!mswTranslateAccelerator( mswWin->hWnd, &msg )) ) { + TranslateMessage( &msg ); + } + DispatchMessage( &msg ); + } +} + +/** + * Timer callback function for the pause timer. The only purpose of this + * timer proc is to clear the waiting flag and kill the timer itself. + */ +void CALLBACK TimerProc( HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ) +{ + if (idEvent == PAUSE_TIMER) { + paused = FALSE; + KillTimer( hWnd, PAUSE_TIMER ); + } +} + +/** + * Pause the application for a specified time. + */ + +void wPause( long msec ) +{ + paused = TRUE; + if (msec > 65000L) + msec = 65000L; + pauseTimer = SetTimer( mswHWnd, PAUSE_TIMER, (UINT)msec, TimerProc ); + if (pauseTimer == 0) + mswFail("wPause: No timers"); + else + pausedLoop(); +} + + +void wAlarm( + long msec, + wAlarmCallBack_p func ) +{ + alarmFunc = func; + if (msec > 65000L) + msec = 65000L; + alarmTimer = SetTimer( mswHWnd, ALARM_TIMER, (UINT)msec, NULL ); + if (alarmTimer == 0) + mswFail("wAlarm: No timers"); +} + + +void mswSetTrigger( + wControl_p control, + setTriggerCallback_p func ) +{ + UINT msec = (UINT)500; + triggerControl = control; + triggerFunc = func; + if (func == NULL && triggerTimer != 0) { + KillTimer( mswHWnd, triggerTimer ); + triggerTimer = 0; + return; + } + if (msec > 65000L) + msec = 65000L; + triggerTimer = SetTimer( mswHWnd, TRIGGER_TIMER, (UINT)msec, NULL ); + if (triggerTimer == 0) + mswFail("wAlarm: No timers"); +} + + +void wBeep( void ) +{ + MessageBeep( MB_OK ); +} + +/** + * Show a notification window with a yes/no reply and an icon. + * + * \param type IN type of message: Information, Warning, Error + * \param msg IN message to display + * \param yes IN text for accept button + * \param no IN text for cancel button + * \return True when accept was selected, false otherwise + */ + +int wNoticeEx( + int type, + const char * msg, + const char * yes, + const char * no ) +{ + int res; + UINT flag; + char *headline; + + switch( type ) { + case NT_INFORMATION: + flag = MB_ICONINFORMATION; + headline = _("Information"); + break; + case NT_WARNING: + flag = MB_ICONWARNING; + headline = _("Warning"); + break; + case NT_ERROR: + flag = MB_ICONERROR; + headline = _("Error"); + break; + } + res = MessageBox( mswHWnd, msg, headline, flag | MB_TASKMODAL|((no==NULL)?MB_OK:MB_YESNO) ); + return res == IDOK || res == IDYES; +} + +int wNotice( + const char * msg, + const char * yes, + const char * no ) +{ + int res; + res = MessageBox( mswHWnd, msg, "Notice", MB_TASKMODAL|((no==NULL)?MB_OK:MB_YESNO) ); + return res == IDOK || res == IDYES; +} + +/** + * Show a notification window with three choices and an icon. + * + * \param msg IN message to display + * \param yes IN text for yes button + * \param no IN text for no button + * \param cancel IN text for cancel button + * \return 1 for yes, -1 for no, 0 for cancel + */ + + +int wNotice3( + const char * msg, + const char * yes, + const char * no, + const char * cancel ) +{ + int res; + res = MessageBox( mswHWnd, msg, _("Warning"), MB_ICONWARNING | MB_TASKMODAL|MB_YESNOCANCEL ); + if ( res == IDOK || res == IDYES ) + return 1; + else if ( res == IDNO ) + return -1; + else + return 0; +} + + +void wHelp( + const char * topic ) +{ + char *pszHelpTopic; + HWND hwndHelp; + + if (!helpInitted) { + HtmlHelp( NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie) ; + helpInitted = TRUE; + } +/* "c:\\help.chm::/intro.htm>mainwin", */ + /* attention: always adapt constant value (10) to needed number of formatting characters */ + pszHelpTopic = malloc( strlen( helpFile ) + strlen( topic ) + 10 ); + assert( pszHelpTopic != NULL ); + + sprintf( pszHelpTopic, "/%s.html", topic ); + hwndHelp = HtmlHelp(mswHWnd, helpFile, HH_DISPLAY_TOPIC, (DWORD_PTR)pszHelpTopic); + if( !hwndHelp ) + wNoticeEx( NT_ERROR, pszHelpTopic, "Ok", NULL ); + + free( pszHelpTopic ); +} + + +void doHelpMenu( void * context ) +{ + HH_FTS_QUERY ftsQuery; + + if( !helpInitted ) { + HtmlHelp( NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie) ; + helpInitted = TRUE; + } + + switch ((int)(long)context) { + case 1: /* Contents */ + HtmlHelp( mswHWnd, helpFile, HH_DISPLAY_TOC, (DWORD_PTR)NULL ); + break; + case 2: /* Search */ + ftsQuery.cbStruct = sizeof( ftsQuery ); + ftsQuery.fExecute = FALSE; + ftsQuery.fStemmedSearch = FALSE; + ftsQuery.fTitleOnly = FALSE; + ftsQuery.pszSearchQuery = NULL; + ftsQuery.pszWindow = NULL; + + HtmlHelp( mswHWnd, helpFile, HH_DISPLAY_SEARCH,(DWORD)&ftsQuery ); + break; + default: + return; + } + helpInitted = TRUE; +} + +void wMenuAddHelp( + wMenu_p m ) +{ + wMenuPushCreate( m, NULL, "&Contents", 0, doHelpMenu, (void*)1 ); + wMenuPushCreate( m, NULL, "&Search for Help on...", 0, doHelpMenu, (void*)2 ); +} + + +void wSetBalloonHelp( wBalloonHelp_t * bh ) +{ + balloonHelpStrings = bh; +} + + +void wEnableBalloonHelp( int enable ) +{ + balloonHelpEnable = enable; +} + + +void wBalloonHelpUpdate ( void ) +{ +} + + +void wControlSetBalloonText( wControl_p b, const char * text ) +{ + b->tipStr = mswStrdup( text ); +} + + +void startBalloonHelp( void ) +{ + HDC hDc; + DWORD extent; + int w, h; + RECT rect; + POINT pt; + wBalloonHelp_t * bh; + const char * hs; + HFONT hFont; + + if (!balloonHelpStrings) + return; + if (!balloonHelpEnable) + return; + if (balloonHelpHWnd) { + if ( balloonHelpButton->tipStr ) { + hs = balloonHelpButton->tipStr; + } else { + hs = balloonHelpButton->helpStr; + if (!hs) + return; + for ( bh = balloonHelpStrings; bh->name && strcmp(bh->name,hs) != 0; bh++ ); + if (!bh->name || !bh->value) + return; + balloonHelpButton->tipStr = hs = bh->value; + } +if (newHelp) { + wControlSetBalloon( balloonHelpButton, 0, 0, hs ); +} else { + hDc = GetDC( balloonHelpHWnd ); + hFont = SelectObject( hDc, mswLabelFont ); + extent = GetTextExtent( hDc, CAST_AWAY_CONST hs, strlen(hs) ); + w = LOWORD( extent ); + h = HIWORD( extent ); + pt.x = 0; + if ( balloonHelpButton->type == B_RADIO || + balloonHelpButton->type == B_TOGGLE ) { + pt.y = balloonHelpButton->h; + } else { + GetClientRect( balloonHelpButton->hWnd, &rect ); + pt.y = rect.bottom; + } + ClientToScreen( balloonHelpButton->hWnd, &pt ); + if (pt.x + w+2 > screenWidth) + pt.x = screenWidth-(w+2); + if (pt.x < 0) + pt.x = 0; + SetWindowPos( balloonHelpHWnd, HWND_TOPMOST, pt.x, pt.y, w+6, h+4, + SWP_SHOWWINDOW|SWP_NOACTIVATE ); + SetBkColor( hDc, GetSysColor( COLOR_INFOBK )); + TextOut( hDc, 2, 1, hs, strlen(hs) ); + SelectObject( hDc, hFont ); + ReleaseDC( balloonHelpHWnd, hDc ); +} + } +} + +void closeBalloonHelp( void ) +{ + if (balloonHelpTimer) { + KillTimer( mswHWnd, balloonHelpTimer ); + balloonHelpTimer = 0; + } + if (balloonHelpState == balloonHelpShow) + if (balloonHelpHWnd) + ShowWindow( balloonHelpHWnd, SW_HIDE ); + balloonHelpState = balloonHelpIdle; +} + + +void wControlSetBalloon( wControl_p b, wPos_t dx, wPos_t dy, const char * msg ) +{ + HDC hDc; + DWORD extent; + int w, h; + RECT rect; + POINT pt; + HFONT hFont; + + if ( msg ) { + hDc = GetDC( balloonHelpHWnd ); + hFont = SelectObject( hDc, mswLabelFont ); + extent = GetTextExtent( hDc, CAST_AWAY_CONST msg, strlen(msg) ); + w = LOWORD( extent ); + h = HIWORD( extent ); + if ( b->type == B_RADIO || + b->type == B_TOGGLE ) { + pt.y = b->h; + } else { + GetClientRect( b->hWnd, &rect ); + pt.y = rect.bottom; + } + pt.x = dx; + pt.y -= dy; + ClientToScreen( b->hWnd, &pt ); + if (pt.x + w+2 > screenWidth) + pt.x = screenWidth-(w+2); + if (pt.x < 0) + pt.x = 0; + SetWindowPos( balloonHelpHWnd, HWND_TOPMOST, pt.x, pt.y, w+6, h+4, + SWP_SHOWWINDOW|SWP_NOACTIVATE ); + SetBkColor( hDc, GetSysColor( COLOR_INFOBK ) ); + TextOut( hDc, 2, 1, msg, strlen(msg) ); + SelectObject( hDc, hFont ); + ReleaseDC( balloonHelpHWnd, hDc ); + + balloonHelpState = balloonHelpShow; + balloonControlButton = b; + } else { + closeBalloonHelp(); + } +} + + +int wGetKeyState( void ) +{ + int rc, keyState; + rc = 0; + keyState = GetAsyncKeyState( VK_SHIFT ); + if (keyState & 0x8000) + rc |= WKEY_SHIFT; + keyState = GetAsyncKeyState( VK_CONTROL ); + if (keyState & 0x8000) + rc |= WKEY_CTRL; + keyState = GetAsyncKeyState( VK_MENU ); + if (keyState & 0x8000) + rc |= WKEY_ALT; + return rc; +} + + +/* + ****************************************************************************** + * + * File Selection + * + ****************************************************************************** + */ + +FILE * wFileOpen( + const char * fileName, + const char * mode ) +{ + return fopen( fileName, mode ); +} + + +struct wFilSel_t { + wWin_p parent; + wFilSelMode_e mode; + int option; + const char * title; + char * extList; + wFilSelCallBack_p action; + void * data; + }; + +static char selFileName[1024]; +static char selFileTitle[1024]; +static char sysDirName[1024]; + +int wFilSelect( + struct wFilSel_t * fs, + const char * dirName ) +{ + int rc; + OPENFILENAME ofn; + char * fileName; + const char * ext; + char defExt[4]; + int i; + + if (dirName == NULL || + dirName[0] == '\0' || + strcmp(dirName, ".") == 0 ) { + GetSystemDirectory( CAST_AWAY_CONST (dirName = sysDirName), sizeof sysDirName ); + } + memset( &ofn, 0, sizeof ofn ); + ofn.lStructSize = sizeof ofn; + ofn.hwndOwner = mswHWnd; + ofn.lpstrFilter = fs->extList; + ofn.nFilterIndex = 0; + selFileName[0] = '\0'; + ofn.lpstrFile = selFileName; + ofn.nMaxFile = sizeof selFileName; + selFileTitle[0] = '\0'; + ofn.lpstrFileTitle = selFileTitle; + ofn.nMaxFileTitle = sizeof selFileTitle; + ofn.lpstrInitialDir = dirName; + ofn.lpstrTitle = fs->title; + ext = fs->extList + strlen(fs->extList)+1; + if (*ext++ == '*' && *ext++ == '.') { + for ( i=0; i<3 && ext[i] && ext[i]!=';'; i++ ) + defExt[i] = ext[i]; + defExt[i] = '\0'; + } else { + defExt[0] = '\0'; + } + ofn.lpstrDefExt = defExt; + ofn.Flags |= OFN_LONGFILENAMES; + if (fs->mode == FS_LOAD) { + ofn.Flags |= OFN_FILEMUSTEXIST; + rc = GetOpenFileName( &ofn ); + } else if (fs->mode == FS_SAVE) { + ofn.Flags |= OFN_OVERWRITEPROMPT; + rc = GetSaveFileName( &ofn ); + } else if (fs->mode == FS_UPDATE) { + rc = GetSaveFileName( &ofn ); + } else + return FALSE; + if (!rc) + return FALSE; + fileName = strrchr( selFileName, '\\' ); + if (fileName == NULL) { + mswFail( "wFilSelect: cant extract fileName" ); + return FALSE; + } + fs->action( selFileName, fileName+1, fs->data ); + return TRUE; +} + + +struct wFilSel_t * wFilSelCreate( + wWin_p parent, + wFilSelMode_e mode, + int option, + const char * title, + const char * extList, + wFilSelCallBack_p action, + void * data ) +{ + char * cp; + struct wFilSel_t * ret; + int len; + ret = (struct wFilSel_t*)malloc(sizeof *ret); + ret->parent = parent; + ret->mode = mode; + ret->option = option; + ret->title = mswStrdup(title); + len = strlen(extList); + ret->extList = (char*)malloc(len+2); + strcpy(ret->extList,extList); + for ( cp=ret->extList; *cp; cp++ ) { + if (*cp == '|') + *cp = '\0'; + } + *++cp = '\0'; + ret->action = action; + ret->data = data; + return ret; +} + + +const char * wMemStats( void ) +{ + int rc; + static char msg[80]; + long usedSize = 0; + long usedCnt = 0; + long freeSize = 0; + long freeCnt = 0; + _HEAPINFO heapinfo; + heapinfo._pentry = NULL; + + while ( (rc=_heapwalk( &heapinfo )) == _HEAPOK ) { + switch (heapinfo._useflag) { + case _FREEENTRY: + freeSize += (long)heapinfo._size; + freeCnt++; + break; + case _USEDENTRY: + usedSize += (long)heapinfo._size; + usedCnt++; + break; + } + } + + sprintf( msg, "Used: %ld(%ld), Free %ld(%ld)%s", + usedSize, usedCnt, freeSize, freeCnt, + (rc==_HEAPOK)?"": + (rc==_HEAPEMPTY)?"": + (rc==_HEAPBADBEGIN)?", BADBEGIN": + (rc==_HEAPEND)?"": + (rc==_HEAPBADPTR)?", BADPTR": + ", Unknown Heap Status" ); + return msg; +} + +/* + ***************************************************************************** + * + * Main + * + ***************************************************************************** + */ + +static wControl_p getControlFromCursor( HWND hWnd, wWin_p * winR ) +{ + POINT pt; + wWin_p w; + wControl_p b; + wIndex_t inx; + HWND hTopWnd; + + if (winR) + *winR = NULL; + GetCursorPos( &pt ); + hTopWnd = GetActiveWindow(); + inx = GetWindowWord( hWnd, 0 ); + if ( inx < CONTROL_BASE || inx > controlMap_da.cnt ) { + /* Unknown control */ + /*MessageBeep( MB_ICONEXCLAMATION );*/ + return NULL; + } + w=(wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + return NULL; + if (w->type != W_MAIN && w->type != W_POPUP) + return NULL; + if ( winR ) + *winR = w; + ScreenToClient( hWnd, &pt ); + for (b = w->first; b; b=b->next) { + if (b->type == B_BOX || b->type == B_LINES) + continue; + if (b->hWnd == NULL) + continue; + if (IsWindowVisible( b->hWnd ) == FALSE) + continue; + if (pt.x > b->x && pt.x < b->x+b->w && + pt.y > b->y && pt.y < b->y+b->h ) + return b; + } + return b; +} + +/** + * Window function for the main window and all popup windows. + * + */ + +LRESULT +FAR +PASCAL +MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + int inx; + wWin_p w; + wControl_p b, oldW; + int child = ((GetWindowLong( hWnd, GWL_STYLE) & WS_CHILD) != 0); + POS_T newW, newH; + RECT rect; + PAINTSTRUCT ps; + HWND hWnd2; + LRESULT ret; + HDC hDc; + wAccelKey_e extChar; + + switch (message) { + + case WM_MOUSEWHEEL: + inx = GetWindowWord( hWnd, 0 ); + b = getControlFromCursor( hWnd, NULL ); + if( b && b->type == B_DRAW ) + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) + return mswCallBacks[b->type]->messageProc( (wControl_p)b, hWnd, + message, wParam, lParam ); + return( 0 ); + case WM_DRAWITEM: + case WM_COMMAND: + case WM_MEASUREITEM: + case WM_NOTVALID: + if (WCMD_PARAM_ID == IDM_DOHELP) { + b = getControlFromCursor( hWnd, NULL ); + closeBalloonHelp(); + if (!b) + return 0L; + if (b->helpStr) + wHelp( b->helpStr ); + return 0L; + } + closeBalloonHelp(); + if (WCMD_PARAM_ID < CONTROL_BASE || WCMD_PARAM_ID > (WPARAM)controlMap_da.cnt) + break; + b = controlMap(WCMD_PARAM_ID-CONTROL_BASE).b; + if (!b) + break; + if( b->type == B_BITMAP ) { + // draw the bitmap + mswDrawIcon(((LPDRAWITEMSTRUCT)lParam)->hDC, 0, 0, (wIcon_p)(b->data), FALSE, (COLORREF)0, (COLORREF)0 ); + return( TRUE ); + } else { + mswSetFocus( b ); + ret = 0L; + if (!inMainWndProc) { + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, hWnd, message, wParam, lParam ); + } + inMainWndProc = FALSE; + } + return ret; + } + case WM_PAINT: + inx = GetWindowWord( hWnd, 0 ); + if (inx >= CONTROL_BASE && inx <= controlMap_da.cnt && + (w = (wWin_p)controlMap(inx-CONTROL_BASE).b) && + (w->type == W_MAIN || w->type == W_POPUP) && + (!IsIconic(mswHWnd)) && + (GetUpdateRect( hWnd, &rect, FALSE ) ) ) { + BeginPaint( hWnd, &ps ); + for (b=w->first; b; b=b->next ) { + if (b->shown && + mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->repaintProc) + mswCallBacks[b->type]->repaintProc( hWnd, b ); + } + EndPaint( hWnd, &ps ); + return 1L; + } + break; + + case WM_SIZE: + inx = GetWindowWord( hWnd, 0 ); + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_MAIN && w->type != W_POPUP) + break; + if (w->busy) + break; + switch( wParam ) { + case SIZE_MAXIMIZED: + case SIZE_MINIMIZED: + case SIZE_RESTORED: + newW = LOWORD( lParam ); /* WIN32?? */ + newH = HIWORD( lParam ); /* WIN32?? */ + if (newW <= 0 || newH <= 0) + break; + if (newW == w->w && newH == w->h) + break; + GetWindowRect( w->hWnd, &rect ); + GetClientRect( w->hWnd, &rect ); + InvalidateRect( w->hWnd, NULL, TRUE ); + w->w = newW; + w->h = newH; + if (w->winProc) + w->winProc( w, wResize_e, w->data ); + break; + default: + break; + } + break; + + case WM_CHAR: + case WM_KEYUP: + inx = GetWindowWord( hWnd, 0 ); + if ( inx < CONTROL_BASE || inx > controlMap_da.cnt ) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_MAIN && w->type != W_POPUP) { + if (mswCallBacks[w->type] != NULL && + mswCallBacks[w->type]->messageProc) + return mswCallBacks[w->type]->messageProc( (wControl_p)w, hWnd, + message, wParam, lParam ); + break; + } + extChar = translateExtKey( WCMD_PARAM_ID ); + if (message == WM_KEYUP ) { + if (extChar == wAccelKey_None) + break; + if (extChar == wAccelKey_Back) + break; + } + b = getControlFromCursor( hWnd, NULL ); + closeBalloonHelp(); + if (b && b->type == B_DRAW) { + return SendMessage( b->hWnd, WM_CHAR, wParam, lParam ); + } + switch (WCMD_PARAM_ID) { + case 0x0D: + /* CR - push default button */ + for (b=w->first; b; b=b->next) { + if (b->type == B_BUTTON && (b->option & BB_DEFAULT) != 0) { + inMainWndProc = TRUE; + if (mswCallBacks[B_BUTTON] != NULL && + mswCallBacks[B_BUTTON]->messageProc) { + ret = mswCallBacks[B_BUTTON]->messageProc( b, b->hWnd, + WM_COMMAND, wParam, lParam ); + } + inMainWndProc = FALSE; + break; + } + } + return 0L; + case 0x1B: + /* ESC - push cancel button */ + for (b=w->first; b; b=b->next) { + if (b->type == B_BUTTON && (b->option & BB_CANCEL) != 0) { + inMainWndProc = TRUE; + if (mswCallBacks[B_BUTTON] != NULL && + mswCallBacks[B_BUTTON]->messageProc) { + ret = mswCallBacks[B_BUTTON]->messageProc( b, b->hWnd, + WM_COMMAND, wParam, lParam ); + } + inMainWndProc = FALSE; + break; + } + } + mswSetTrigger( (wControl_p)TRIGGER_TIMER, NULL ); + return 0L; + case 0x20: + /* SPC - push current button with focus */ + if ( (b=w->focusChainNext) != NULL ) { + switch (b->type) { + case B_BUTTON: + case B_CHOICEITEM: + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, b->hWnd, + WM_COMMAND, MAKELPARAM( LOWORD(wParam), BN_CLICKED), (LPARAM)(b->hWnd) ); + } + inMainWndProc = FALSE; + break; + } + } + return 0L; + case 0x09: + /* TAB - jump to next control */ + if ( w->focusChainNext ) { + for ( b = w->focusChainNext->focusChainNext; + b!=w->focusChainNext; + b=b->focusChainNext ) { + if( IsWindowVisible(b->hWnd) && IsWindowEnabled(b->hWnd)) + break; + } + oldW = w->focusChainNext; + w->focusChainNext = b; + if (!inMainWndProc) { + inMainWndProc = TRUE; + SetFocus( b->hWnd ); +/* if( b->type == B_BUTTON) + InvalidateRect( b->hWnd, NULL, TRUE ); */ + if( oldW->type == B_BUTTON) + InvalidateRect( oldW->hWnd, NULL, TRUE ); + + inMainWndProc = FALSE; + } + } + return 0L; + } + /* Not a Draw control */ + MessageBeep( MB_ICONHAND ); + return 0L; + break; + + case WM_ENABLE: + if (wParam == 1) { /* WIN32??? */ + hWnd2 = SetFocus( hWnd ); + } + break; + + case WM_F1DOWN: + if ((hWnd2 = GetActiveWindow()) == hWnd || + (inx=GetWindowWord(hWnd2,0)) < CONTROL_BASE || inx > controlMap_da.cnt ) + return DefWindowProc( hWnd, message, wParam, lParam ); + b=controlMap(inx-CONTROL_BASE).b; + if (!b) + break; + closeBalloonHelp(); + wHelp( b->helpStr ); + return 0L; + + case WM_SETCURSOR: + /*if (any buttons down) + break;*/ + wSetCursor( curCursor ); + if (!mswAllowBalloonHelp) + break; + if (IsIconic(mswHWnd)) + break; + b = getControlFromCursor(hWnd, NULL); + if ( b == balloonControlButton ) + break; + if ( /*(!IsWindowEnabled(hWnd))*/ GetActiveWindow() != hWnd || + (!b) || b->type == B_DRAW || b->helpStr == NULL ) { + closeBalloonHelp(); + break; + } + if ( b != balloonHelpButton ) + closeBalloonHelp(); + if (balloonHelpState != balloonHelpIdle) { + break; + } + balloonHelpTimer = SetTimer( mswHWnd, BALLOONHELP_TIMER, + balloonHelpTimeOut, NULL ); + if (balloonHelpTimer == (UINT)0) + break; + balloonHelpState = balloonHelpWait; + balloonHelpButton = b; + break; + + case WM_SYSCOMMAND: + inx = GetWindowWord( hWnd, 0 ); + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_POPUP) + break; + if (w->busy) + break; + if ( (wParam&0xFFF0) != SC_CLOSE ) + break; + if (w->winProc) + w->winProc( w, wClose_e, w->data ); + wWinShow( w, FALSE ); + return 0L; + + + + case WM_CLOSE: + inx = GetWindowWord( hWnd, 0 ); + if (inx < CONTROL_BASE || inx > controlMap_da.cnt) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type == W_MAIN) { + /* It's the big one! */ + /* call main window procedure for processing of shutdown */ + if( w->winProc ) + (w->winProc( w, wClose_e, NULL )); + return 0L; + } + + case WM_DESTROY: + if ( hWnd == mswHWnd ) { + PostQuitMessage(0L); + return 0L; + } + break; + + case WM_TIMER: + if (wParam == ALARM_TIMER) { + KillTimer( mswHWnd, alarmTimer ); + alarmFunc(); + } else if (wParam == TRIGGER_TIMER) { + KillTimer( mswHWnd, triggerTimer ); + triggerTimer = 0; + if (triggerFunc) + triggerFunc( triggerControl ); + } else if (wParam == BALLOONHELP_TIMER) { + KillTimer( hWnd, balloonHelpTimer ); + balloonHelpTimer = (UINT)0; + startBalloonHelp(); + } + return 0L; + + case WM_MENUSELECT: + mswAllowBalloonHelp = TRUE; + closeBalloonHelp(); + break; + + case WM_WINDOWPOSCHANGED: + if (hWnd == mswHWnd && !IsIconic(hWnd) && needToDoPendingShow) { + for (w=winFirst; w; w=(wWin_p)w->next) { + if (w->hWnd != mswHWnd && + w->pendingShow ) + ShowWindow( w->hWnd, SW_SHOW ); + w->pendingShow = FALSE; + } + needToDoPendingShow = FALSE; + } + break; + + case 51: + count51++; + /*return NULL;*/ + +#ifdef LATER + case WM_SETFOCUS: + hDc = GetDC( hWnd ); + rc = RealizePalette( hDc ); + ReleaseDC( hWnd, hDc ); + inx = GetWindowWord( hWnd, 0 ); + if ( inx < CONTROL_BASE || inx > controlMap_da.cnt ) + break; + w = (wWin_p)controlMap(inx-CONTROL_BASE).b; + if (!w) + break; + if (w->type != W_MAIN && w->type != W_POPUP) + break; + for (b=w->first; b; b=b->next) { + if (b->hWnd && (b->type == B_BUTTON || b->type==B_DRAW)) { + hDc = GetDC( b->hWnd ); + rc = RealizePalette( hDc ); + ReleaseDC( b->hWnd, hDc ); + } + } + break; +#endif + + case WM_PALETTECHANGED: + if (wParam == (WPARAM)hWnd) + return 0L; + + case WM_QUERYNEWPALETTE: + if (mswPalette) { + hDc = GetDC( hWnd ); + SelectPalette( hDc, mswPalette, 0 ); + inx = RealizePalette( hDc ); + ReleaseDC( hWnd, hDc ); + if (inx>0) + InvalidateRect( hWnd, NULL, TRUE ); + return inx; + } + + case WM_ACTIVATE: + if ( LOWORD(wParam) == WA_INACTIVE ) + closeBalloonHelp(); + break; + + case WM_HSCROLL: + case WM_VSCROLL: + b = getControlFromCursor( hWnd, NULL ); + if (!b) + break; + /*mswSetFocus( b );*/ + ret = 0L; + if (!inMainWndProc) { + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, hWnd, message, wParam, lParam ); + } + inMainWndProc = FALSE; + } + return ret; + + case WM_LBUTTONDOWN: + case WM_MOUSEMOVE: + case WM_LBUTTONUP: + b = getControlFromCursor( hWnd, NULL ); + if (!b) + break; + /*mswSetFocus( b );*/ + ret = 0L; + if (!inMainWndProc) { + inMainWndProc = TRUE; + if (mswCallBacks[b->type] != NULL && + mswCallBacks[b->type]->messageProc) { + ret = mswCallBacks[b->type]->messageProc( b, hWnd, message, wParam, lParam ); + } + inMainWndProc = FALSE; + } + return ret; + + default: + ; + } + return DefWindowProc( hWnd, message, wParam, lParam ); +} + +/* + ***************************************************************************** + * + * INIT + * + ***************************************************************************** + */ + +/** + * Register window classes used by the application. These are the main window, + * the popup windows, the tooltip window and the drawing area. + * + * \param hinstCurrent IN application instance + * \return FALSE in case of error, else TRUE + */ + +static BOOL InitApplication( HINSTANCE hinstCurrent ) +{ + WNDCLASS wc; + + wc.style = 0L; + wc.lpfnWndProc = MainWndProc; + + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; + wc.hInstance = hinstCurrent; + wc.hIcon = LoadIcon( hinstCurrent, "MSWAPPICON" ); + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = "MswMainWindow"; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(MainWindow)"); + return FALSE; + } + + wc.style = CS_SAVEBITS; + wc.lpfnWndProc = MainWndProc; + + wc.cbClsExtra = 0; + wc.cbWndExtra = 8; + wc.hInstance = hinstCurrent; + wc.hIcon = LoadIcon( NULL, "wAppIcon" ); + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wc.lpszMenuName = "GenericMenu"; + wc.lpszClassName = "MswPopUpWindow"; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(PopUpWindow)"); + return FALSE; + } + + wc.style = CS_SAVEBITS; + wc.lpfnWndProc = DefWindowProc; + + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; + wc.hInstance = hinstCurrent; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = CreateSolidBrush( GetSysColor( COLOR_INFOBK ) ); + wc.lpszMenuName = NULL; + wc.lpszClassName = "MswBalloonHelp"; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(BalloonHelp)"); + return FALSE; + } + + wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; + wc.lpfnWndProc = mswDrawPush; + wc.lpszClassName = mswDrawWindowClassName; + wc.cbWndExtra = 4; + if (!RegisterClass(&wc)) { + mswFail("RegisterClass(drawClass)"); + return FALSE; + } + return TRUE; +} + +/** + * Standard entry point for the app. Nothing special, + * create some window classes, initialize some global + * variables with system information, call the application main + * and finally process the message queue. + */ + +int PASCAL WinMain( HINSTANCE hinstCurrent, HINSTANCE hinstPrevious, LPSTR lpszCmdLine, int nCmdShow ) +{ + MSG msg; + HDC hDc; + char **argv; + int argc; + TEXTMETRIC tm; + DWORD dw; + + if (!hinstPrevious) + if (!InitApplication(hinstCurrent)) + return FALSE; + + mswHInst = hinstCurrent; + + mTitleH = GetSystemMetrics( SM_CYCAPTION ) - 1; + mFixBorderW = GetSystemMetrics( SM_CXBORDER ); + mFixBorderH = GetSystemMetrics( SM_CYBORDER ); + mResizeBorderW = GetSystemMetrics( SM_CXFRAME ); + mResizeBorderH = GetSystemMetrics( SM_CYFRAME ); + mMenuH = GetSystemMetrics( SM_CYMENU ) + 1; + screenWidth = GetSystemMetrics( SM_CXSCREEN ); + screenHeight = GetSystemMetrics( SM_CYSCREEN ); + mswLabelFont = GetStockObject( DEFAULT_GUI_FONT ); + + hDc = GetDC( 0 ); + mswScale = GetDeviceCaps( hDc, LOGPIXELSX ) / 96.0; + if ( mswScale < 1.0 ) + mswScale = 1.0; + GetTextMetrics( hDc, &tm ); + mswEditHeight = tm.tmHeight + 8; + dw = GetTextExtent( hDc, "AXqypj", 6 ); + mswEditHeight = HIWORD(dw)+2; + ReleaseDC( 0, hDc ); + + mswCreateCheckBitmaps(); + + /* + get the command line parameters in standard C style and pass them to the main function. The + globals are predefined by Visual C + */ + argc = __argc; + argv = __argv; + + mswWin = wMain( argc, (char**)argv ); + if (mswWin == NULL) + return 0; + + balloonHelpHWnd = CreateWindow( "MswBalloonHelp", "BalloonHelp", + WS_POPUP|WS_BORDER, + 0, 0, 80, 40, mswHWnd, NULL, mswHInst, NULL ); + if (balloonHelpHWnd == (HWND)0) { + mswFail( "CreateWindow(BALLOONHELP)" ); + } else { + hDc = GetDC( balloonHelpHWnd ); + /* We need to remember this because the hDc gets changed somehow, + /* and we when we select the oldFont back in we don't get newFont */ + balloonHelpNewFont = CreateFont( - balloonHelpFontSize, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, balloonHelpFaceName ); + balloonHelpOldFont = SelectObject( hDc, balloonHelpNewFont ); + ReleaseDC( balloonHelpHWnd, hDc ); + } + + SetCursor( LoadCursor( NULL, IDC_ARROW ) ); + while (GetMessage( &msg, NULL, 0, 0 )) { + if (!mswTranslateAccelerator( mswWin->hWnd, &msg )) { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } + + if( helpInitted == TRUE ) + HtmlHelp( NULL, NULL, HH_UNINITIALIZE, (DWORD)dwCookie); + + return msg.wParam; +} diff --git a/app/wlib/mswlib/mswmsg.c b/app/wlib/mswlib/mswmsg.c new file mode 100644 index 0000000..b128534 --- /dev/null +++ b/app/wlib/mswlib/mswmsg.c @@ -0,0 +1,212 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Message Boxes + * + ***************************************************************************** + */ + +/** + * factors by which fonts are resized if nonstandard text height is used + */ + +#define SCALE_LARGE 1.6 +#define SCALE_SMALL 0.8 + +#ifdef CONTROL3D +static int messageHeight = 18; +#endif + +struct wMessage_t { + WOBJ_COMMON + long flags; + const char * message; + }; + +#ifndef CONTROL3D +static void repaintMessage( + HWND hWnd, + wControl_p b ) +{ + wMessage_p bm = (wMessage_p)b; + HDC hDc; + RECT rect; + HFONT hFont; + LOGFONT msgFont; + double scale = 1.0; + + hDc = GetDC( hWnd ); + + if ( !mswThickFont ) + hFont = SelectObject( hDc, mswLabelFont ); + + switch( wMessageSetFont( ((wMessage_p)b)->flags )) + { + case BM_LARGE: + scale = SCALE_LARGE; + break; + case BM_SMALL: + scale = SCALE_SMALL; + break; + } + + /* is a non-standard text height required? */ + if( scale != 1.0 ) + { + /* if yes, get information about the standard font used */ + GetObject( GetStockObject( DEFAULT_GUI_FONT ), sizeof( LOGFONT ), &msgFont ); + + /* change the height */ + msgFont.lfHeight = (long)((double)msgFont.lfHeight * scale); + + /* create and activate the new font */ + hFont = SelectObject( hDc, CreateFontIndirect( &msgFont ) ); + } else { + if ( !mswThickFont ) + hFont = SelectObject( hDc, mswLabelFont ); + } + + rect.bottom = (long)(bm->y+( bm->h )); + rect.right = (long)(bm->x+( scale * bm->w )); + rect.top = bm->y; + rect.left = bm->x; + + SetBkColor( hDc, GetSysColor( COLOR_BTNFACE ) ); + ExtTextOut( hDc, bm->x, bm->y, ETO_CLIPPED|ETO_OPAQUE, &rect, bm->message, strlen( bm->message ), NULL ); + + if( scale != 1.0 ) + /* in case we did create a new font earlier, delete it now */ + DeleteObject( SelectObject( hDc, GetStockObject( DEFAULT_GUI_FONT ))); + else + if ( !mswThickFont ) + SelectObject( hDc, hFont ); + + ReleaseDC( hWnd, hDc ); +} +#endif + +void wMessageSetValue( + wMessage_p b, + const char * arg ) +{ + if (b->message) + free( CAST_AWAY_CONST b->message ); + if (arg) + b->message = mswStrdup( arg ); + else + b->message = NULL; +#ifdef CONTROL3D + SetWindowText( b->hWnd, arg ); +#else + repaintMessage( ((wControl_p)(b->parent))->hWnd, (wControl_p)b ); +#endif +} + +void wMessageSetWidth( + wMessage_p b, + wPos_t width ) +{ + b->w = width; +#ifdef CONTROL3D + SetWindowPos( b->hWnd, HWND_TOP, CW_USEDEFAULT, CW_USEDEFAULT, + width, messageHeight, SWP_NOMOVE ); +#endif +} + + +wPos_t wMessageGetHeight( long flags ) +{ +#ifdef CONTROL3D + return messageHeight; +#else + double scale = 1.0; + + if( flags & BM_LARGE ) + scale = SCALE_LARGE; + if( flags & BM_SMALL ) + scale = SCALE_SMALL; + + return((wPos_t)((mswEditHeight - 4) * scale )); +#endif +} + +static void mswMessageSetBusy( + wControl_p b, + BOOL_T busy ) +{ +} + + +#ifndef CONTROL3D +static callBacks_t messageCallBacks = { + repaintMessage, + NULL, + NULL, + mswMessageSetBusy }; +#endif + + +wMessage_p wMessageCreateEx( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + POS_T width, + const char *message, + long flags ) +{ + wMessage_p b; + int index; + +#ifdef CONTROL3D + RECT rect; +#endif + + b = (wMessage_p)mswAlloc( parent, B_MESSAGE, NULL, sizeof *b, NULL, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option |= BO_READONLY; + b->message = mswStrdup( message ); + b->flags = flags; + +#ifdef CONTROL3D + if ( width <= 0 && strlen(b->message) > 0 ) { + width = wLabelWidth( b->message ); + } + + b->hWnd = CreateWindow( "STATIC", NULL, + SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE, + b->x, b->y, + width, messageHeight, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(MESSAGE)"); + return b; + } + + if ( !mswThickFont ) + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + SetWindowText( b->hWnd, message ); + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; +#else + b->w = width; + b->h = wMessageGetHeight( flags ) + 1; + + repaintMessage( ((wControl_p)parent)->hWnd, (wControl_p)b ); +#endif + mswAddButton( (wControl_p)b, FALSE, helpStr ); +#ifndef CONTROL3D + mswCallBacks[B_MESSAGE] = &messageCallBacks; +#endif + return b; +} diff --git a/app/wlib/mswlib/mswpref.c b/app/wlib/mswlib/mswpref.c new file mode 100644 index 0000000..90cf8fc --- /dev/null +++ b/app/wlib/mswlib/mswpref.c @@ -0,0 +1,274 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <stdio.h> +#include "mswint.h" +#include <shlobj.h> +#include <Shlwapi.h> + +#if _MSC_VER >=1400 + #define stricmp _stricmp +#endif + +char * mswStrdup( const char * ); +static char appLibDirName[MAX_PATH]; +static char appWorkDirName[MAX_PATH]; + +/** + * Get the location of the shared files (parameters, help file, etc. ): This location is + * derived from the modulename, ie. the directory where the exe is installed. + * For an instalaltion directory of somedir/bin/xtrkcad.exe the library directory is + * somedir/share/xtrkcad/ + */ + +const char * wGetAppLibDir( void ) +{ + char *cp; + char module_name[MAX_PATH]; + + if (appLibDirName[0] != '\0') { + return appLibDirName; + } + + GetModuleFileName( mswHInst, module_name, sizeof module_name ); + cp = strrchr( module_name, '\\' ); + if (cp) + *cp = '\0'; + +#ifdef XTRKCAD_CMAKE_BUILD + strcpy(appLibDirName, module_name); + strcat(appLibDirName, "\\..\\share\\xtrkcad"); + _fullpath( appLibDirName, appLibDirName, MAX_PATH ); + return appLibDirName; +#endif + + strcpy(appLibDirName, module_name); + return appLibDirName; +} + + +/** + * Gets the working directory for the application. At least the INI file is stored here. + * The working directory can be specified manually by creating a file called xtrkcad0.ini + * in the application lib dir (the directory where the .EXE is located). + * + * [workdir] + * path=somepath + * + * when somepath is set to the keyword "installdir", the install directory for the EXE is + * used. + * + * If no xtrkcad0.ini could be found, the user settings directory (appdata) is used. + * + */ +const char * wGetAppWorkDir( void ) +{ + char *cp; + int rc; + if ( appWorkDirName[0] != 0 ) { + return appWorkDirName; + } + wGetAppLibDir(); + sprintf( mswTmpBuff, "%s\\xtrkcad0.ini", appLibDirName ); + rc = GetPrivateProfileString( "workdir", "path", "", appWorkDirName, sizeof appWorkDirName, mswTmpBuff ); + if ( rc!=0 ) { + if ( stricmp( appWorkDirName, "installdir" ) == 0 ) { + strcpy( appWorkDirName, appLibDirName ); + } else { + cp = &appWorkDirName[strlen(appWorkDirName)-1]; + while (cp>appWorkDirName && *cp == '\\') *cp-- = 0; + } + return appWorkDirName; + } + + if (SHGetSpecialFolderPath( NULL, mswTmpBuff, CSIDL_APPDATA, 0 ) == 0 ) { + wNoticeEx( NT_ERROR, "Cannot get user's profile directory", "Exit", NULL ); + wExit(0); + } else { + sprintf( appWorkDirName, "%s\\%s", mswTmpBuff, "XTrackCad" ); + if( !PathIsDirectory( appWorkDirName )) { + if( !CreateDirectory( appWorkDirName, NULL )) { + wNoticeEx( NT_ERROR, "Cannot create user's profile directory", "Exit", NULL ); + wExit(0); + } + } + } + + return appWorkDirName; +} + +/** Get the user's home directory. The environment variable HOME is + * assumed to contain the proper directory. + * + * \return pointer to the user's home directory + */ + +const char *wGetUserHomeDir( void ) +{ + if (SHGetSpecialFolderPath( NULL, mswTmpBuff, CSIDL_PERSONAL, 0 ) == 0 ) { + wNoticeEx( NT_ERROR, "Cannot get user's home directory", "Exit", NULL ); + wExit(0); + return( NULL ); + } else { + return( mswTmpBuff ); + } +} + +typedef struct { + char * section; + char * name; + BOOL_T present; + BOOL_T dirty; + char * val; + } prefs_t; +dynArr_t prefs_da; +#define prefs(N) DYNARR_N(prefs_t,prefs_da,N) + +void wPrefSetString( const char * section, const char * name, const char * sval ) +{ + prefs_t * p; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if ( strcmp( p->section, section ) == 0 && strcmp( p->name, name ) == 0 ) { + if (p->val) + free(p->val); + p->dirty = TRUE; + p->val = mswStrdup( sval ); + return; + } + } + DYNARR_APPEND( prefs_t, prefs_da, 10 ); + p = &prefs(prefs_da.cnt-1); + p->name = mswStrdup(name); + p->section = mswStrdup(section); + p->dirty = TRUE; + p->val = mswStrdup(sval); +} + + +const char * wPrefGetString( const char * section, const char * name ) +{ + prefs_t * p; + int rc; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if ( strcmp( p->section, section ) == 0 && strcmp( p->name, name ) == 0 ) { + return p->val; + } + } + rc = GetPrivateProfileString( section, name, "", mswTmpBuff, sizeof mswTmpBuff, mswProfileFile ); + if (rc==0) + return NULL; + DYNARR_APPEND( prefs_t, prefs_da, 10 ); + p = &prefs(prefs_da.cnt-1); + p->name = mswStrdup(name); + p->section = mswStrdup(section); + p->dirty = FALSE; + p->val = mswStrdup(mswTmpBuff); + return p->val; +} + + +void wPrefSetInteger( const char * section, const char * name, long lval ) +{ + char tmp[20]; + + sprintf( tmp, "%ld", lval ); + wPrefSetString( section, name, tmp ); +} + + +wBool_t wPrefGetInteger( + const char * section, + const char * name, + long *res, + long def ) +{ + const char * cp; + char * cp1; + + cp = wPrefGetString( section, name ); + if (cp == NULL) { + *res = def; + return FALSE; + } + *res = strtol(cp,&cp1,0); + if (cp==cp1) { + *res = def; + return FALSE; + } + return TRUE; +} + + +void wPrefSetFloat( + const char * section, /* Section */ + const char * name, /* Name */ + double lval ) /* Value */ +/* +*/ +{ + char tmp[20]; + + sprintf(tmp, "%0.6f", lval ); + wPrefSetString( section, name, tmp ); +} + + +wBool_t wPrefGetFloat( + const char * section, /* Section */ + const char * name, /* Name */ + double * res, /* Address of result */ + double def ) /* Default value */ +/* +*/ +{ + const char * cp; + char * cp1; + + cp = wPrefGetString( section, name ); + if (cp == NULL) { + *res = def; + return FALSE; + } + *res = strtod(cp, &cp1); + if (cp == cp1) { + *res = def; + return FALSE; + } + return TRUE; +} + + +void wPrefFlush( void ) +{ + prefs_t * p; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if ( p->dirty ) + WritePrivateProfileString( p->section, p->name, p->val, mswProfileFile ); + } + WritePrivateProfileString( NULL, NULL, NULL, mswProfileFile ); +} + + +void wPrefReset( + void ) +/* +*/ +{ + prefs_t * p; + + for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { + if (p->section) + free( p->section ); + if (p->name) + free( p->name ); + if (p->val) + free( p->val ); + } + prefs_da.cnt = 0; +} diff --git a/app/wlib/mswlib/mswprint.c b/app/wlib/mswlib/mswprint.c new file mode 100644 index 0000000..91f05ea --- /dev/null +++ b/app/wlib/mswlib/mswprint.c @@ -0,0 +1,387 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#ifndef WIN32 +#include <print.h> +#endif +#include "mswint.h" + +/* + ***************************************************************************** + * + * PRINT + * + ***************************************************************************** + */ + + +struct wDraw_t print_d; + +#ifdef WIN32 +struct tagPDA printDlg; +#else +struct tagPD printDlg; +#endif +static int printStatus = FALSE; +static DOCINFO docInfo; +static double pageSizeW = 8.5, pageSizeH = 11.0; +static double physSizeW = 8.5, physSizeH = 11.0; +static int pageCount = -1; + +static HPALETTE newPrintPalette; +static HPALETTE oldPrintPalette; + + +void wPrintClip( wPos_t x, wPos_t y, wPos_t w, wPos_t h ) +{ + wDrawClip( &print_d, x, y, w, h ); +} + + +void getPageDim( HDC hDc ) +{ + int rc; + POINT dims; + POINT offs; + int res_w, res_h, size_w, size_h; + rc = Escape( hDc, GETPHYSPAGESIZE, 0, NULL, (LPPOINT)&dims ); + if (rc <0) { + mswFail( "GETPHYPAGESIZE" ); + } + rc = Escape( hDc, GETPRINTINGOFFSET, 0, NULL, (LPPOINT)&offs ); + if (rc <0) { + mswFail( "GETPRINTINGOFFSET" ); + } + print_d.wFactor = (double)GetDeviceCaps( hDc, LOGPIXELSX ); + print_d.hFactor = (double)GetDeviceCaps( hDc, LOGPIXELSY ); + if (print_d.wFactor <= 0 || print_d.hFactor <= 0) { + mswFail( "getPageDim: LOGPIXELS... <= 0" ); + abort(); + } + print_d.DPI = min( print_d.wFactor, print_d.hFactor ); + size_w = GetDeviceCaps( hDc, HORZSIZE ); + size_h = GetDeviceCaps( hDc, VERTSIZE ); + print_d.w = res_w = GetDeviceCaps( hDc, HORZRES ); + print_d.h = res_h = GetDeviceCaps( hDc, VERTRES ); + pageSizeW = ((double)res_w)/print_d.wFactor; + pageSizeH = ((double)res_h)/print_d.hFactor; + physSizeW = ((double)dims.x)/print_d.wFactor; + physSizeH = ((double)dims.y)/print_d.hFactor; +} + +static wBool_t printInit( void ) +{ + static int initted = FALSE; + static int printerOk = FALSE; + if (initted) { + if (!printerOk) { + mswFail( "No Printers are defined" ); + } + return printerOk; + } + initted = TRUE; + printDlg.lStructSize = sizeof printDlg; + printDlg.hwndOwner = NULL; + printDlg.Flags = PD_RETURNDC|PD_RETURNDEFAULT; + if (PrintDlg(&printDlg) != 0 && printDlg.hDC) { + getPageDim( printDlg.hDC ); + DeleteDC( printDlg.hDC ); + } +#ifdef LATER + DEVMODE * printMode; + HDC hDc; + char ptrInfo[80]; + char ptrDrvrDvr[80]; + char *temp; + char *ptrDevice; + char *ptrDrvr; + char *ptrPort; + int size; + int rc; + FARPROC extDeviceMode; + FARPROC deviceMode; + HINSTANCE hDriver; + + GetProfileString("windows", "device", "", ptrInfo, sizeof ptrInfo ); + if (ptrInfo[0] == 0) { + mswFail( "No Printers are defined" ); + return FALSE; + } + temp = ptrDevice = ptrInfo; + ptrDrvr = ptrPort = NULL; + while (*temp) { + if (*temp == ',') { + *temp++ = 0; + while( *temp == ' ' ) + temp++; + if (!ptrDrvr) + ptrDrvr = temp; + else { + ptrPort = temp; + break; + } + } + else + temp = AnsiNext(temp); + } + strcpy( ptrDrvrDvr, ptrDrvr ); + strcat( ptrDrvrDvr, ".drv" ); + if ((long)(hDriver = LoadLibrary( ptrDrvrDvr )) <= 32) { + mswFail( "printInit: LoadLibrary" ); + return FALSE; + } + if (( extDeviceMode = GetProcAddress( hDriver, "ExtDeviceMode" )) != NULL) { + size = extDeviceMode( mswHWnd, (HANDLE)hDriver, (LPDEVMODE)NULL, (LPSTR)ptrDevice, (LPSTR)ptrPort, (LPDEVMODE)NULL, (LPSTR)NULL, 0 ); + printMode = (DEVMODE*)malloc( size ); + rc = extDeviceMode( mswHWnd, (HANDLE)hDriver, (LPDEVMODE)printMode, (LPSTR)ptrDevice, (LPSTR)ptrPort, (LPDEVMODE)NULL, (LPSTR)NULL, DM_OUT_BUFFER ); +#ifdef LATER + if (rc != IDOK && rc != IDCANCEL) { + mswFail( "printInit: extDeviceMode" ); + return FALSE; + } +#endif + } else if (( deviceMode = GetProcAddress( hDriver, "DeviceMode" )) != NULL) { + rc = deviceMode( mswHWnd, (HANDLE)hDriver, (LPSTR)ptrDevice, (LPSTR)ptrPort ); +#ifdef LATER + if (rc != IDOK && rc != IDCANCEL) { + mswFail( "printInit: deviceMode" ); + return FALSE; + } +#endif + } + + hDc = CreateDC( (LPSTR)ptrDrvr, (LPSTR)ptrDevice, (LPSTR)ptrPort, NULL ); + if (hDc == NULL) { + mswFail("printInit: createDC" ); + abort(); + } + getPageDim( hDc ); + DeleteDC( hDc ); + + FreeLibrary( hDriver ); +#endif + printerOk = TRUE; + return TRUE; +} + + +wBool_t wPrintInit( void ) +{ + if (!printInit()) { + return FALSE; + } + return TRUE; +} + + +void wPrintSetup( wPrintSetupCallBack_p callback ) +{ + if (!printInit()) { + return; + } + /*memset( &printDlg, 0, sizeof printDlg );*/ + printDlg.lStructSize = sizeof printDlg; + printDlg.hwndOwner = NULL; + printDlg.Flags = PD_RETURNDC|PD_PRINTSETUP; + if (PrintDlg(&printDlg) != 0 && printDlg.hDC) { + getPageDim( printDlg.hDC ); + } + if ( callback ) { + callback( TRUE ); + } +} + + +void wPrintGetPageSize( double *w, double *h ) +{ + printInit(); + *w = pageSizeW; + *h = pageSizeH; +} + + +void wPrintGetPhysSize( double *w, double *h ) +{ + printInit(); + *w = physSizeW; + *h = physSizeH; +} + + +HDC mswGetPrinterDC( void ) +{ + if (!printInit()) { + return (HDC)0; + } + /*memset( &printDlg, 0, sizeof printDlg );*/ + printDlg.lStructSize = sizeof printDlg; + printDlg.hwndOwner = NULL; + printDlg.Flags = PD_RETURNDC|PD_NOPAGENUMS|PD_NOSELECTION; + if (PrintDlg(&printDlg) != 0) + return printDlg.hDC; + else + return (HDC)0; +} + + +static wBool_t printAbort = FALSE; +HWND hAbortDlgWnd; +FARPROC lpAbortDlg, lpAbortProc; +static int pageNumber; + +int FAR PASCAL mswAbortDlg( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + if (msg == WM_COMMAND) { + if (WCMD_PARAM_ID == IDCANCEL) { + printAbort = TRUE; + EndDialog( hWnd, wParam ); + return TRUE; + } + } else if (msg == WM_INITDIALOG) { + SetFocus( GetDlgItem( hWnd, IDCANCEL ) ); + return TRUE; + } + return FALSE; +} + + +int FAR PASCAL _export mswAbortProc( HDC hdcPrinter, int Code ) +{ + MSG msg; + while (PeekMessage((LPMSG)&msg, (HWND)0, 0, 0, PM_REMOVE)) { + if (!IsDialogMessage(hAbortDlgWnd, (LPMSG)&msg) ) { + TranslateMessage( (LPMSG)&msg ); + DispatchMessage( (LPMSG)&msg ); + } + } + return !printAbort; +} + + +wBool_t wPrintDocStart( const char * title, int fpageCount, int * copiesP ) +{ + printStatus = FALSE; + pageCount = fpageCount; + pageNumber = 0; + print_d.hDc = mswGetPrinterDC(); + if (print_d.hDc == (HDC)0) { + return FALSE; + } + printStatus = TRUE; + docInfo.cbSize = sizeof docInfo; + docInfo.lpszDocName = title; + docInfo.lpszOutput = NULL; + lpAbortDlg = MakeProcInstance( (FARPROC)mswAbortDlg, mswHInst ); + lpAbortProc = MakeProcInstance( (FARPROC)mswAbortProc, mswHInst ); + SetAbortProc( print_d.hDc, (ABORTPROC)lpAbortProc ); + if (StartDoc( print_d.hDc, &docInfo ) < 0) { + MessageBox( mswHWnd, "Unable to start print job", + NULL, MB_OK|MB_ICONHAND ); + FreeProcInstance( lpAbortDlg ); + FreeProcInstance( lpAbortProc ); + DeleteDC( print_d.hDc ); + return FALSE; + } + printAbort = FALSE; + hAbortDlgWnd = CreateDialog( mswHInst, "MswAbortDlg", mswHWnd, + (DLGPROC)lpAbortDlg ); + /*SetDlgItemText( hAbortDlgWnd, IDM_PRINTAPP, title );*/ + SetWindowText( hAbortDlgWnd, title ); + ShowWindow( hAbortDlgWnd, SW_NORMAL ); + UpdateWindow( hAbortDlgWnd ); + EnableWindow( mswHWnd, FALSE ); + if (copiesP) + *copiesP = printDlg.nCopies; + if (printDlg.nCopies>1) + pageCount *= printDlg.nCopies; + if ( (GetDeviceCaps( printDlg.hDC, RASTERCAPS ) & RC_PALETTE) ) { + newPrintPalette = mswCreatePalette(); + oldPrintPalette = SelectPalette( printDlg.hDC, newPrintPalette, 0 ); + RealizePalette( printDlg.hDC ); + } + return TRUE; +} + +wDraw_p wPrintPageStart( void ) +{ + char pageL[80]; + if (!printStatus) + return NULL; + pageNumber++; + if (pageCount > 0) + wsprintf( pageL, "Page %d of %d", pageNumber, pageCount ); + else + wsprintf( pageL, "Page %d", pageNumber ); + SetDlgItemText( hAbortDlgWnd, IDM_PRINTPAGE, pageL ); + StartPage( printDlg.hDC ); +#ifdef LATER + if (mswPrintPalette) { + SelectPalette( printDlg.hDC, mswPrintPalette, 0 ); + RealizePalette( printDlg.hDC ); + } +#endif + getPageDim( printDlg.hDC ); + SelectClipRgn( print_d.hDc, NULL ); + return &print_d; +} + +wBool_t wPrintPageEnd( wDraw_p d ) +{ + return EndPage( printDlg.hDC ) >= 0; +} + +wBool_t wPrintQuit( void ) +{ + MSG msg; + while (PeekMessage((LPMSG)&msg, (HWND)0, 0, 0, PM_REMOVE)) { + if (!IsDialogMessage(hAbortDlgWnd, (LPMSG)&msg) ) { + TranslateMessage( (LPMSG)&msg ); + DispatchMessage( (LPMSG)&msg ); + } + } + return printAbort; +} + +void wPrintDocEnd( void ) +{ + if (!printStatus) + return; + EndDoc( printDlg.hDC ); + if ( newPrintPalette ) { + SelectPalette( printDlg.hDC, oldPrintPalette, 0 ); + DeleteObject( newPrintPalette ); + newPrintPalette = (HPALETTE)0; + } + + EnableWindow( mswHWnd, TRUE ); + DestroyWindow( hAbortDlgWnd ); + FreeProcInstance( lpAbortDlg ); + FreeProcInstance( lpAbortProc ); + DeleteDC( printDlg.hDC ); + printStatus = FALSE; +} + +wBool_t wPrintFontAlias( const char * font, const char * alias ) +{ + return TRUE; +} + +wBool_t wPrintNewPrinter( const char * printer ) +{ + return TRUE; +} + +wBool_t wPrintNewMargin( const char * name, double t, double b, double l, double r ) +{ + return TRUE; +} + +void wPrintSetCallBacks( + wAddPrinterCallBack_p newPrinter, + wAddMarginCallBack_p newMargin, + wAddFontAliasCallBack_p newFontAlias ) +{ +} diff --git a/app/wlib/mswlib/mswsplash.c b/app/wlib/mswlib/mswsplash.c new file mode 100644 index 0000000..bddd081 --- /dev/null +++ b/app/wlib/mswlib/mswsplash.c @@ -0,0 +1,266 @@ +/** + * Splash window for Windows + * $header$ + */ + + /* XTrkCad - Model Railroad CAD + * Copyright (C) 2007 Martin Fischer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <ctype.h> +#include <assert.h> +#include "mswint.h" + +extern HINSTANCE mswHInst; +extern HWND mswHWnd; + +static HWND hSplash; + +#define IDAPPNAME 150 +#define IDMESSAGE 200 +#define IDBITMAP 250 + +static LPWORD lpwAlign( LPWORD lpIn ) +{ + ULONG ul; + + ul = (ULONG) lpIn; + ul +=3; + ul >>=2; + ul <<=2; + return (LPWORD) ul; +} + +/** + * Draw the logo bitmap. Thanks to Charles Petzold. + */ + +BOOL +PaintBitmap( HWND hWnd, HBITMAP hBmp ) +{ + HDC hdc, hdcMem; + RECT rect; + + UpdateWindow( hWnd ); + + /* get device context for destination window ( the dialog control ) */ + hdc = GetDC( hWnd ); + GetClientRect( hWnd, &rect ); + + /* create a memory dc holding the bitmap */ + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdcMem, hBmp ); + + /* + show it in the uppler left corner + the window is created with the size of the bitmap, so there is no need + for any special transformation + */ + + BitBlt( hdc, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, + hdcMem, 0, 0, SRCCOPY ); + + /* release the DCs that are not needed any more */ + DeleteDC( hdcMem ); + ReleaseDC( hWnd, hdc ); + + return( 0 ); +} + +/** + * This is the dialog procedure for the splash window. Main activity is to + * catch the WM_PAINT message and draw the logo bitmap into that area. + */ + +BOOL CALLBACK +SplashDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static HWND hWndBmp; + static HBITMAP hBmp; + + switch( msg ) { + case WM_INITDIALOG: + /* bitmap handle is passed at dialog creation */ + hBmp = (HBITMAP)lParam; + + hWndBmp = GetDlgItem( hDlg, IDBITMAP ); + return TRUE; + case WM_PAINT: + /* paint the logo bitmap */ + PaintBitmap( hWndBmp, hBmp ); + break; + case WM_DESTROY: + /* destroy the bitmap */ + DeleteObject( hBmp ); + break; + } + return FALSE; +} + +/** + * Show the splash screen. For display of the splash screen, a dialog template is + * created in memory. This template has three static elements: + * - the logo + * - the application name + * - the progress message + * + * return TRUE if successful, FALSE otherwise. + * + */ + +int +wCreateSplash( char *appname, char *appver ) +{ + HGLOBAL hgbl; + LPDLGTEMPLATE lpdt; + LPWORD lpw; + LPDLGITEMTEMPLATE lpdit; + int cxDlgUnit, cyDlgUnit; + int cx, cy; + char *pszBuf; + HBITMAP hBmp; + BITMAP bmp; + char logoPath[MAX_PATH]; + + /* find the size of a dialog unit */ + cxDlgUnit = LOWORD(GetDialogBaseUnits()); + cyDlgUnit = HIWORD(GetDialogBaseUnits()); + + /* load the logo bitmap */ + sprintf( logoPath, "%s\\logo.bmp", wGetAppLibDir()); + hBmp = LoadImage( mswHInst, logoPath, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_LOADFROMFILE ); + if( !hBmp ) + return( 0 ); + + /* get info about the loaded logo file */ + GetObject( hBmp, sizeof(BITMAP), (LPVOID)&bmp ); + + /* calculate the size of dialog box */ + cx = (bmp.bmWidth * 4) / cxDlgUnit; /* start with the size of the bitmap */ + cy = (bmp.bmHeight * 8) / cyDlgUnit + 20; /* 20 is enough for two lines of text and some room */ + + /* allocate memory block for dialog template */ + hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024); + if (!hgbl) + return -1; + lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl); + + /* Define a dialog box. */ + lpdt->style = WS_POPUP | WS_BORDER | WS_VISIBLE | DS_MODALFRAME | DS_CENTER; + lpdt->cdit = 3; // number of controls + lpdt->x = 0; lpdt->y = 0; + lpdt->cx = cx; lpdt->cy = cy; + + lpw = (LPWORD) (lpdt + 1); + *lpw++ = 0; /* no menu */ + *lpw++ = 0; /* predefined dialog box class (by default) */ + *lpw++ = 0; + + /* add the static control for the logo bitmap */ + lpdit = (LPDLGITEMTEMPLATE)lpwAlign(lpw); + lpdit->x = 0; lpdit->y = 0; + lpdit->cx = (SHORT)((bmp.bmWidth * 4) / cxDlgUnit); + lpdit->cy = (SHORT)((bmp.bmHeight * 8) / cyDlgUnit); + + lpdit->id = IDBITMAP; + lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT; + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; /* static class */ + + lpw += 1+MultiByteToWideChar (CP_ACP, 0, "Logo should be here...", -1, (LPWSTR)lpw, 50); + + /* add the static control for the program title */ + lpdit = (LPDLGITEMTEMPLATE)lpwAlign(lpw); + + lpdit->x = 2; lpdit->y = (short)( 1 + (bmp.bmHeight * 8) / cyDlgUnit ); + lpdit->cx = cx - 2; lpdit->cy = cyDlgUnit; + lpdit->id = IDAPPNAME; + lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER; + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; /* static class */ + + /* create the title string */ + pszBuf = malloc( strlen( appname ) + strlen( appver ) + 2 ); + if( !pszBuf ) + return( 0 ); + sprintf( pszBuf, "%s %s", appname, appver ); + + lpw += 1+MultiByteToWideChar (CP_ACP, 0, pszBuf, -1, (LPWSTR)lpw, 50); + + /* add the static control for the loading message */ + lpdit = (LPDLGITEMTEMPLATE)lpwAlign(lpw); + lpdit->x = 2; lpdit->y = (short)(bmp.bmHeight * 8) / cyDlgUnit + 10; + lpdit->cx = cx - 2; lpdit->cy = cyDlgUnit; + lpdit->id = IDMESSAGE; + lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT; + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; /* static class */ + + lpw += 1+MultiByteToWideChar (CP_ACP, 0, "Starting Application...", -1, (LPWSTR)lpw, 50); + + /* create the dialog */ + GlobalUnlock(hgbl); + hSplash = CreateDialogIndirectParam( mswHInst, (LPDLGTEMPLATE) hgbl, + mswHWnd, (DLGPROC)SplashDlgProc, (LPARAM)hBmp ); + GetLastError(); + + /* free allocated memory */ + GlobalFree(hgbl); + free( pszBuf ); + + /* that's it */ + return 1; +} + + +/** + * Update the progress message inside the splash window + * msg text message to display + * return nonzero if ok + */ + +int +wSetSplashInfo( char *msg ) +{ + if( msg ) { + SetWindowText( GetDlgItem( hSplash, IDMESSAGE ), msg ); + wFlush(); + return TRUE; + } + wFlush(); + return FALSE; +} + +/** + * Remove the splash window from the screen. + */ + +void +wDestroySplash(void) +{ + DestroyWindow( hSplash ); + return; +}
\ No newline at end of file diff --git a/app/wlib/mswlib/mswtext.c b/app/wlib/mswlib/mswtext.c new file mode 100644 index 0000000..95f6268 --- /dev/null +++ b/app/wlib/mswlib/mswtext.c @@ -0,0 +1,383 @@ +#include <windows.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <commdlg.h> +#include <math.h> +#include <stdio.h> +#include "mswint.h" + +/* + ***************************************************************************** + * + * Multi-line Text Boxes + * + ***************************************************************************** + */ + +static LOGFONT fixedFont = { + /* Initial default values */ + -18, 0, /* H, W */ + 0, /* A */ + 0, + FW_REGULAR, + 0, 0, 0,/* I, U, SO */ + ANSI_CHARSET, + 0, /* OP */ + 0, /* CP */ + 0, /* Q */ + FIXED_PITCH|FF_MODERN, /* P&F */ + "Courier" }; +static HFONT fixedTextFont, prevTextFont; + +struct wText_t { + WOBJ_COMMON + HANDLE hText; + }; + +BOOL_T textPrintAbort = FALSE; + + +void wTextClear( + wText_p b ) +{ + long rc; + rc = SendMessage( b->hWnd, EM_SETREADONLY, 0, 0L ); +#ifdef WIN32 + rc = SendMessage( b->hWnd, EM_SETSEL, 0, -1 ); +#else + rc = SendMessage( b->hWnd, EM_SETSEL, 1, MAKELONG( 0, -1 ) ); +#endif + rc = SendMessage( b->hWnd, WM_CLEAR, 0, 0L ); + if ( b->option&BO_READONLY ) + rc = SendMessage( b->hWnd, EM_SETREADONLY, 1, 0L ); +} + + +void wTextAppend( + wText_p b, + const char * text ) +{ + HANDLE hMem; + char * pMem, *cp; + int len, textSize; + long rc; + long lc; + len = strlen(text); + if (len <= 0) + return; + for (cp= CAST_AWAY_CONST text; *cp; cp++) { + if ( *cp == '\n' ) + len++; + } + hMem = GlobalAlloc( GHND, (DWORD)len+10+1 ); + pMem = (char*)GlobalLock( hMem ); + for (cp=pMem; *text; cp++,text++) { + if (*text == '\n') { + *cp++ = '\r'; + *cp = '\n'; + } else + *cp = *text; + } + textSize = LocalSize( b->hText ); + if ((long)textSize+(long)len > 10000L) { + if (len < 1024) + len = 1024; +#ifdef WIN32 + rc = SendMessage( b->hWnd, EM_SETSEL, 0, len ); +#else + rc = SendMessage( b->hWnd, EM_SETSEL, 0, MAKELONG( 0, len ) ); +#endif + rc = SendMessage( b->hWnd, WM_CLEAR, 0, 0L ); +#ifdef WIN32 + rc = SendMessage( b->hWnd, EM_SCROLLCARET, 0, 0 ); +#else + rc = SendMessage( b->hWnd, EM_SETSEL, 0, MAKELONG( 32767, 32767 ) ); +#endif + } + lc = SendMessage( b->hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L ); + if ( lc < 0 ) + lc = 0; + GlobalUnlock( hMem ); + rc = OpenClipboard( b->hWnd ); + rc = EmptyClipboard(); + rc = (long)SetClipboardData( CF_TEXT, hMem ); + rc = CloseClipboard(); + rc = SendMessage( b->hWnd, EM_SETREADONLY, 0, 0L ); + rc = SendMessage( b->hWnd, WM_PASTE, 0, 0L ); + lc -= SendMessage( b->hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L ); +#ifdef LATER + if ( lc < 0 ) + SendMessage( b->hWnd, EM_LINESCROLL, 0, MAKELPARAM((WPARAM)lc,0) ); +#endif + lc = GetWindowTextLength( b->hWnd ); + if ( b->option&BO_READONLY ) + rc = SendMessage( b->hWnd, EM_SETREADONLY, 1, 0L ); +} + + +BOOL_T wTextSave( + wText_p b, + const char * fileName ) +{ + FILE * f; + int lc, l, len; + char line[255]; + + f = wFileOpen( fileName, "w" ); + if (f == NULL) { + MessageBox( ((wControl_p)(b->parent))->hWnd, "TextSave", "", MB_OK|MB_ICONHAND ); + return FALSE; + } + + lc = (int)SendMessage( b->hWnd, EM_GETLINECOUNT, 0, 0L ); + + for ( l=0; l<lc; l++ ) { + *(WORD*)line = sizeof(line)-1; + len = (int)SendMessage( b->hWnd, EM_GETLINE, l, (DWORD)(LPSTR)line ); + line[len] = '\0'; + fprintf( f, "%s\n", line ); + } + fclose( f ); + return TRUE; +} + + +BOOL_T wTextPrint( + wText_p b ) +{ + int lc, l, len; + char line[255]; + HDC hDc; + int lineSpace; + int linesPerPage; + int currentLine; + int IOStatus; + TEXTMETRIC textMetric; + DOCINFO docInfo; + + hDc = mswGetPrinterDC(); + if (hDc == (HDC)0) { + MessageBox( ((wControl_p)(b->parent))->hWnd, "Print", "Cannot print", MB_OK|MB_ICONHAND ); + return FALSE; + } + docInfo.cbSize = sizeof(DOCINFO); + docInfo.lpszDocName = "XTrkcad Log"; + docInfo.lpszOutput = (LPSTR)NULL; + if (StartDoc(hDc, &docInfo) < 0) { + MessageBox( ((wControl_p)(b->parent))->hWnd, "Unable to start print job", NULL, MB_OK|MB_ICONHAND ); + DeleteDC( hDc ); + return FALSE; + } + StartPage( hDc ); + GetTextMetrics( hDc, &textMetric ); + lineSpace = textMetric.tmHeight + textMetric.tmExternalLeading; + linesPerPage = GetDeviceCaps( hDc, VERTRES ) / lineSpace; + currentLine = 1; + + lc = (int)SendMessage( b->hWnd, EM_GETLINECOUNT, 0, 0L ); + + IOStatus = 0; + for ( l=0; l<lc; l++ ) { + *(WORD*)line = sizeof(line)-1; + len = (int)SendMessage( b->hWnd, EM_GETLINE, l, (DWORD)(LPSTR)line ); + TextOut( hDc, 0, currentLine*lineSpace, line, len ); + if (++currentLine > linesPerPage) { + EndPage( hDc ); + currentLine = 1; + IOStatus = EndPage(hDc); + if (IOStatus < 0 || textPrintAbort ) + break; + StartPage( hDc ); + } + } + if (IOStatus >= 0 && !textPrintAbort ) { + EndPage( hDc ); + EndDoc( hDc ); + } + DeleteDC( hDc ); + return TRUE; +} + + +wBool_t wTextGetModified( + wText_p b ) +{ + int rc; + rc = (int)SendMessage( b->hWnd, EM_GETMODIFY, 0, 0L ); + return (wBool_t)rc; +} + +int wTextGetSize( + wText_p b ) +{ + int lc, l, li, len=0; + lc = (int)SendMessage( b->hWnd, EM_GETLINECOUNT, 0, 0L ); + for ( l=0; l<lc ; l++ ) { + li = (int)SendMessage( b->hWnd, EM_LINEINDEX, l, 0L ); + len += (int)SendMessage( b->hWnd, EM_LINELENGTH, l, 0L ) + 1; + } + if ( len == 1 ) + len = 0; + return len; +} + +void wTextGetText( + wText_p b, + char * t, + int s ) +{ + int lc, l, len; + s--; + lc = (int)SendMessage( b->hWnd, EM_GETLINECOUNT, 0, 0L ); + for ( l=0; l<lc && s>=0; l++ ) { + *(WORD*)t = s; + len = (int)SendMessage( b->hWnd, EM_GETLINE, l, (DWORD)(LPSTR)t ); + t += len; + *t++ = '\n'; + s -= len+1; + } + *t++ = '\0'; +} + + +void wTextSetReadonly( + wText_p b, + wBool_t ro ) +{ + if (ro) + b->option |= BO_READONLY; + else + b->option &= ~BO_READONLY; + SendMessage( b->hWnd, EM_SETREADONLY, ro, 0L ); +} + + +void wTextSetSize( + wText_p bt, + wPos_t width, + wPos_t height ) +{ + bt->w = width; + bt->h = height; + if (!SetWindowPos( bt->hWnd, HWND_TOP, 0, 0, + bt->w, bt->h, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("wTextSetSize: SetWindowPos"); + } +} + + +void wTextComputeSize( + wText_p bt, + int rows, + int lines, + wPos_t * w, + wPos_t * h ) +{ + static wPos_t scrollV_w = -1; + static wPos_t scrollH_h = -1; + HDC hDc; + TEXTMETRIC metrics; + + if (scrollV_w < 0) + scrollV_w = GetSystemMetrics( SM_CXVSCROLL ); + if (scrollH_h < 0) + scrollH_h = GetSystemMetrics( SM_CYHSCROLL ); + hDc = GetDC( bt->hWnd ); + GetTextMetrics( hDc, &metrics ); + *w = rows * metrics.tmAveCharWidth + scrollV_w; + *h = lines * (metrics.tmHeight + metrics.tmExternalLeading); + ReleaseDC( bt->hWnd, hDc ); + if (bt->option&BT_HSCROLL) + *h += scrollH_h; +} + + +void wTextSetPosition( + wText_p bt, + int pos ) +{ + long rc; + rc = SendMessage( bt->hWnd, EM_LINESCROLL, 0, MAKELONG( -65535, 0 ) ); +} + +static void textDoneProc( wControl_p b ) +{ + wText_p t = (wText_p)b; + HDC hDc; + hDc = GetDC( t->hWnd ); + SelectObject( hDc, mswOldTextFont ); + ReleaseDC( t->hWnd, hDc ); +} + +static callBacks_t textCallBacks = { + mswRepaintLabel, + textDoneProc, + NULL }; + +wText_p wTextCreate( + wWin_p parent, + POS_T x, + POS_T y, + const char * helpStr, + const char * labelStr, + long option, + POS_T width, + POS_T height ) +{ + wText_p b; + DWORD style; + RECT rect; + int index; + + b = mswAlloc( parent, B_TEXT, labelStr, sizeof *b, NULL, &index ); + mswComputePos( (wControl_p)b, x, y ); + b->option = option; + style = ES_MULTILINE | ES_LEFT | ES_AUTOVSCROLL | ES_WANTRETURN | + WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL; +#ifdef BT_HSCROLL + if (option & BT_HSCROLL) + style |= WS_HSCROLL | ES_AUTOHSCROLL; +#endif +/* if (option & BO_READONLY) + style |= ES_READONLY;*/ + + b->hWnd = CreateWindow( "EDIT", NULL, + style, b->x, b->y, + width, height, + ((wControl_p)parent)->hWnd, (HMENU)index, mswHInst, NULL ); + if (b->hWnd == NULL) { + mswFail("CreateWindow(TEXT)"); + return b; + } +#ifdef CONTROL3D + Ctl3dSubclassCtl( b->hWnd ); +#endif + + if (option & BT_FIXEDFONT) { + if (fixedTextFont == (HFONT)0) + fixedTextFont = CreateFontIndirect( &fixedFont ); + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)fixedTextFont, (LPARAM)MAKELONG( 1, 0 ) ); + } else if ( !mswThickFont ) { + SendMessage( b->hWnd, WM_SETFONT, (WPARAM)mswLabelFont, 0L ); + } + + b->hText = (HANDLE)SendMessage( b->hWnd, EM_GETHANDLE, 0, 0L ); + + if (option & BT_CHARUNITS) { + wPos_t w, h; + wTextComputeSize( b, width, height, &w, &h ); + if (!SetWindowPos( b->hWnd, HWND_TOP, 0, 0, + w, h, SWP_NOMOVE|SWP_NOZORDER)) { + mswFail("wTextCreate: SetWindowPos"); + } + } + + GetWindowRect( b->hWnd, &rect ); + b->w = rect.right - rect.left; + b->h = rect.bottom - rect.top; + + mswAddButton( (wControl_p)b, FALSE, helpStr ); + mswCallBacks[B_TEXT] = &textCallBacks; + return b; +} diff --git a/app/wlib/mswlib/simple-gettext.c b/app/wlib/mswlib/simple-gettext.c new file mode 100644 index 0000000..295d515 --- /dev/null +++ b/app/wlib/mswlib/simple-gettext.c @@ -0,0 +1,522 @@ +/* simple-gettext.c - a simplified version of gettext. + * Copyright (C) 1995, 1996, 1997, 1999, + * 2005 Free Software Foundation, Inc. + * + * This file is part of XTrackCAD. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* This is a simplified version of gettext written by Ulrich Drepper. + * It is used for the Win32 version of GnuPG beucase all the overhead + * of gettext is not needed and we have to do some special Win32 stuff. + * I decided that this is far easier than to tweak gettext for the special + * cases (I tried it but it is a lot of code). wk 15.09.99 + */ + +/* + * Based on the simple-gettext from GnuPG a version appropriate for the + * needs of XTrackCAD was derived. This is a workaround for any compiler + * specifics or runtime library dependencies. mf 26.07.09 + */ + +#ifdef USE_SIMPLE_GETTEXT +#if !defined (_WIN32) && !defined (__CYGWIN32__) +#error This file can only be used under Windows or Cygwin32 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <windows.h> + +#include "mswint.h" + +#if _MSC_VER > 1300 + #define stricmp _stricmp + #define strnicmp _strnicmp + #define strdup _strdup + #define fileno _fileno +#endif + +typedef unsigned long u32; + +/* The magic number of the GNU message catalog format. */ +#define MAGIC 0x950412de +#define MAGIC_SWAPPED 0xde120495 + +/* Revision number of the currently used .mo (binary) file format. */ +#define MO_REVISION_NUMBER 0 + + +/* Header for binary .mo file format. */ +struct mo_file_header +{ + /* The magic number. */ + u32 magic; + /* The revision number of the file format. */ + u32 revision; + /* The number of strings pairs. */ + u32 nstrings; + /* Offset of table with start offsets of original strings. */ + u32 orig_tab_offset; + /* Offset of table with start offsets of translation strings. */ + u32 trans_tab_offset; + /* Size of hashing table. */ + u32 hash_tab_size; + /* Offset of first hashing entry. */ + u32 hash_tab_offset; +}; + +struct string_desc +{ + /* Length of addressed string. */ + u32 length; + /* Offset of string in file. */ + u32 offset; +}; + + +struct overflow_space_s +{ + struct overflow_space_s *next; + u32 idx; + char d[1]; +}; + +struct loaded_domain +{ + char *data; + int must_swap; + u32 nstrings; + char *mapped; /* 0 = not yet mapped, 1 = mapped, + 2 = mapped to + overflow space */ + struct overflow_space_s *overflow_space; + struct string_desc *orig_tab; + struct string_desc *trans_tab; + u32 hash_size; + u32 *hash_tab; +}; + +static struct loaded_domain *the_domain; + +/** + * Translate the input string from UTF8 to Windows codepage. + * + * \param str IN string in UTF-8 format to translate. + * \param len IN number of chars to translate + * \param dummy IN ? + * \return pointer to translated string. Free after usage + */ +char * +utf8_to_native( char *str, unsigned int len, int dummy ) +{ + /* maximum output length is size of string * 2 */ + int buflen = (len + 1) * 2; + char *buf = malloc( buflen ); + int wcharLen; + /* maximum result size is size of UTF-8 string */ + char *resBuffer = malloc( len + 1 ); + + if( !resBuffer ) { + resBuffer = "ERROR in UTF-8 MALLOC"; + } else { + /* as Windows has no way fo a direct translation fom UTF-8 to */ + /* the system codepage, we need to take two steps */ + + /* 1. convert from UTF-8 to UTF-16 */ + wcharLen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)str, -1, (LPWSTR)buf, buflen / 2 ); + + /* 2. convert from UTF-8 to system codepage */ + WideCharToMultiByte(CP_ACP, 0, (LPWSTR)buf, wcharLen, resBuffer, len + 1, NULL, NULL ); + + free( buf ); + } + return( resBuffer ); +} + + +static u32 +do_swap_u32( u32 i ) +{ + return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); +} + +#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) ) + + +/* We assume to have `unsigned long int' value with at least 32 bits. */ +#define HASHWORDBITS 32 + +/* The so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ + +static unsigned long +hash_string( const char *str_param ) +{ + unsigned long int hval, g; + const char *str = str_param; + + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (unsigned long int) *str++; + g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + + +static struct loaded_domain * +load_domain( const char *filename ) +{ + FILE *fp; + size_t size; + struct stat st; + struct mo_file_header *data = NULL; + struct loaded_domain *domain = NULL; + size_t to_read; + char *read_ptr; + + fp = fopen( filename, "rb" ); + if( !fp ) + return NULL; /* can't open the file */ + /* we must know about the size of the file */ + if( fstat( fileno(fp ), &st ) + || (size = (size_t)st.st_size) != st.st_size + || size < sizeof (struct mo_file_header) ) { + fclose( fp ); + return NULL; + } + + data = malloc( size ); + if( !data ) { + fclose( fp ); + return NULL; /* out of memory */ + } + + to_read = size; + read_ptr = (char *) data; + do { + unsigned long int nb = fread( read_ptr, 1, to_read, fp ); + if( nb < to_read ) { + fclose (fp); + free(data); + return NULL; /* read error */ + } + read_ptr += nb; + to_read -= nb; + } while( to_read > 0 ); + fclose (fp); + + /* Using the magic number we can test whether it really is a message + * catalog file. */ + if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) { + /* The magic number is wrong: not a message catalog file. */ + free( data ); + return NULL; + } + + domain = calloc( 1, sizeof *domain ); + if( !domain ) { + free( data ); + return NULL; + } + domain->data = (char *) data; + domain->must_swap = data->magic != MAGIC; + + /* Fill in the information about the available tables. */ + switch( SWAPIT(domain->must_swap, data->revision) ) { + case 0: + domain->nstrings = SWAPIT(domain->must_swap, data->nstrings); + domain->orig_tab = (struct string_desc *) + ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset)); + domain->trans_tab = (struct string_desc *) + ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); + domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); + domain->hash_tab = (u32 *) + ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); + break; + + default: /* This is an invalid revision. */ + free( data ); + free( domain ); + return NULL; + } + + /* Allocate an array to keep track of code page mappings. */ + domain->mapped = calloc( 1, domain->nstrings ); + if( !domain->mapped ) { + free( data ); + free( domain ); + return NULL; + } + + return domain; +} + + +/** + * Set the file used for translations. Pass a NULL to disable + * translation. A new filename may be set at anytime. WARNING: + * After changing the filename you should not access any data + * retrieved by gettext(). + */ +int +set_gettext_file ( const char *filename, const char *regkey ) +{ + struct loaded_domain *domain = NULL; + + if( filename && *filename ) { + if( filename[0] == '/' + || ( isalpha(filename[0]) + && filename[1] == ':' + && (filename[2] == '/' || filename[2] == '\\') ) + ) { + /* absolute path - use it as is */ + domain = load_domain( filename ); + } + if (!domain) + return -1; + } + + if( the_domain ) { + struct overflow_space_s *os, *os2; + free( the_domain->data ); + free( the_domain->mapped ); + for (os=the_domain->overflow_space; os; os = os2) { + os2 = os->next; + free (os); + } + free( the_domain ); + the_domain = NULL; + } + the_domain = domain; + return 0; +} + +/** + * Return the required string from the message table. Before returning the result, + * codepage translation from UTF8 to current codepage is performed. + */ + +static const char* +get_string( struct loaded_domain *domain, u32 idx ) +{ + struct overflow_space_s *os; + char *p; + + p = domain->data + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset); + if (!domain->mapped[idx]) + { + size_t plen, buflen; + char *buf; + + domain->mapped[idx] = 1; + + plen = strlen (p); + buf = utf8_to_native (p, plen, -1); + buflen = strlen (buf); + if (buflen <= plen){ + strcpy (p, buf); + free( buf ); + } else { + /* There is not enough space for the translation - store it + in the overflow_space else and mark that in the mapped + array. Because we expect that this won't happen too + often, we use a simple linked list. */ + os = malloc (sizeof *os + buflen); + if (os) + { + os->idx = idx; + strcpy (os->d, buf); + os->next = domain->overflow_space; + domain->overflow_space = os; + p = os->d; + } + else + p = "ERROR in GETTEXT MALLOC"; + free (buf); + } + } + else if (domain->mapped[idx] == 2) + { /* We need to get the string from the overflow_space. */ + for (os=domain->overflow_space; os; os = os->next) + if (os->idx == idx) + return (const char*)os->d; + p = "ERROR in GETTEXT\n"; + } + return (const char*)p; +} + +/** + * This is the translation function itself. + */ + +char * +gettext( char *msgid ) +{ + struct loaded_domain *domain; + size_t act = 0; + size_t top, bottom; + + if( !(domain = the_domain) ) + goto not_found; + + /* Locate the MSGID and its translation. */ + if( domain->hash_size > 2 && domain->hash_tab ) { + /* Use the hashing table. */ + u32 len = strlen (msgid); + u32 hash_val = hash_string (msgid); + u32 idx = hash_val % domain->hash_size; + u32 incr = 1 + (hash_val % (domain->hash_size - 2)); + u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); + + if ( !nstr ) /* Hash table entry is empty. */ + goto not_found; + + if( SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].length) == len + && !strcmp( msgid, + domain->data + SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].offset)) ) + return (char *)get_string( domain, nstr - 1 ); + + for(;;) { + if (idx >= domain->hash_size - incr) + idx -= domain->hash_size - incr; + else + idx += incr; + + nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]); + if( !nstr ) + goto not_found; /* Hash table entry is empty. */ + + if ( SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].length) == len + && !strcmp (msgid, + domain->data + SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].offset))) + return (char *)get_string( domain, nstr-1 ); + } + /* NOTREACHED */ + } + + /* Now we try the default method: binary search in the sorted + array of messages. */ + bottom = 0; + top = domain->nstrings; + while( bottom < top ) { + int cmp_val; + + act = (bottom + top) / 2; + cmp_val = strcmp(msgid, domain->data + + SWAPIT(domain->must_swap, + domain->orig_tab[act].offset)); + if (cmp_val < 0) + top = act; + else if (cmp_val > 0) + bottom = act + 1; + else + return (char *)get_string( domain, act ); + } + + not_found: + return msgid; +} + +/** + * This is the main initialization function for simple gettext. The message file is + * opened and read into memory. The function must be called once before translating + * a string. + * + * The message files are expected to be in a directory named in the UNIXish form en_US + * in the path passed to this function. The filename is expected to be domainname.mo + * + * \param domainname IN domain + * \param dirname IN directory for the message files + * \return always NULL + */ + +char * +bindtextdomain( char *domainname, char *dirname ) +{ + char *loc; + char *dir; + + /* get thread's locale in UNIXish style eg. en_US */ + loc = g_win32_getlocale(); + + /* make sure that path does not end with trailing slash */ + if( dirname[ strlen(dirname) ] == '/' ) + dirname[ strlen(dirname) ] = '\0'; + + /* allocate buffer for filename, 20 bytes should be enough for extension etc. */ + dir = malloc( strlen( domainname ) + strlen( dirname ) + strlen( loc ) + 20 ); + + if( dir ) { + /* create the full filename */ + sprintf( dir, "%s/%s/LC_MESSAGES/%s.mo", dirname, loc, domainname ); + /* load the file */ + set_gettext_file( dir, NULL ); + free( dir ); + } + + free( loc ); + return( NULL ); +} + +/** + * This is a dummy function to maintain source code compatibility + * with other implementations of gettext. + * For this implementation, UTF-8 input encoding is assumed + * + * \param domainname IN domain + * \param codeset In codeset + * \return always NULL + */ + +char * +bind_textdomain_codeset(char *domainname, char *codeset ) +{ + return( NULL ); +} + +/** + * This is a dummy function to maintain source code compatibility + * with other implementations of gettext. + * + * \param domainname IN domain + * \return always NULL + */ + +char * +textdomain( char *domainname ) +{ + return( NULL ); +} +#endif /* USE_SIMPLE_GETTEXT */ diff --git a/app/wlib/mswlib/square10.bmp b/app/wlib/mswlib/square10.bmp new file mode 100644 index 0000000..c45fb75 --- /dev/null +++ b/app/wlib/mswlib/square10.bmp @@ -0,0 +1,6 @@ +#define square10_width 14 +#define square10_height 14 +static unsigned char square10_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff}; 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 Binary files differnew file mode 100644 index 0000000..998d604 --- /dev/null +++ b/app/wlib/test/wtest.ico 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"
|