#ifdef INCRCSDATA static char RCSid[]="$Id: gclient.c,v 1.15 1998/03/22 22:34:21 drd Exp $" ; #endif /**************************************************************************** PROGRAM: Gnupmdrv MODULE: gclient.c This file contains the client window procedures for Gnupmdrv ****************************************************************************/ /* PM driver for GNUPLOT */ /*[ * Copyright 1992, 1993, 1998 Roger Fearick * * Permission to use, copy, and distribute this software and its * documentation for any purpose with or without fee is hereby granted, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. * * Permission to modify the software is granted, but not the right to * distribute the complete modified source code. Modifications are to * be distributed as patches to the released version. Permission to * distribute binaries produced by compiling modified sources is granted, * provided you * 1. distribute the corresponding source modifications from the * released version in the form of a patch file along with the binaries, * 2. add special version identification to distinguish your version * in addition to the base release version number, * 3. provide your name and address as the primary contact for the * support of your modified version, and * 4. retain our contact information in regard to use of the base * software. * Permission to distribute the released version of the source code along * with corresponding source modifications in the form of a patch file is * granted with same provisions 2 through 4 for binary distributions. * * This software is provided "as is" without express or implied warranty * to the extent permitted by applicable law. ]*/ /* * AUTHOR * * Gnuplot driver for OS/2: Roger Fearick * * Send your comments or suggestions to * info-gnuplot@dartmouth.edu. * This is a mailing list; to join it send a note to * majordomo@dartmouth.edu. * Send bug reports to * bug-gnuplot@dartmouth.edu. **/ #define INCL_PM #define INCL_WIN #define INCL_SPL #define INCL_SPLDOSPRINT #define INCL_WINSTDFONT #define INCL_DOSMEMMGR #define INCL_DOSPROCESS #define INCL_DOSERRORS #define INCL_DOSFILEMGR #define INCL_DOSNMPIPES #define INCL_DOSSESMGR #define INCL_DOSSEMAPHORES #define INCL_DOSMISC #define INCL_DOSQUEUES #define INCL_WINSWITCHLIST #include #include #include #include #include #include #include #include #include #include #include "gnupmdrv.h" /*==== g l o b a l d a t a ================================================*/ extern char szIPCName[] ; /* name used in IPC with gnuplot */ extern char szIniFile[256] ; /* full path of ini file */ extern int bServer ; extern int bPersist ; extern int bEnhanced ; /*==== l o c a l d a t a ==================================================*/ static long lLineTypes[7] = { LINETYPE_SOLID, LINETYPE_SHORTDASH, LINETYPE_DOT, LINETYPE_DASHDOT, LINETYPE_LONGDASH, LINETYPE_DOUBLEDOT, LINETYPE_DASHDOUBLEDOT } ; static long lCols[16] = { CLR_BLACK, CLR_DARKGRAY, CLR_BLUE, CLR_RED, CLR_GREEN, CLR_CYAN, CLR_PINK, CLR_YELLOW, CLR_DARKBLUE, CLR_DARKRED, CLR_DARKGREEN, CLR_DARKCYAN, CLR_DARKPINK, CLR_BROWN, CLR_PALEGRAY, CLR_WHITE } ; static LONG alColourTable[ 16 ] ; #define GNUBUF 1024 /* buffer for gnuplot commands */ #define PIPEBUF 4096 /* size of pipe buffers */ #define CMDALLOC 4096 /* command buffer allocation increment (ints) */ #define ENVSIZE 2048 /* size of environment */ #define PAUSE_DLG 1 /* pause handled in dialog box */ #define PAUSE_BTN 2 /* pause handled by menu item */ #define PAUSE_GNU 3 /* pause handled by Gnuplot */ #define DEFLW 50 static ULONG ppidGnu=0L ; /* gnuplot pid */ static HPS hpsScreen ; /* screen pres. space */ static int iSeg = 1 ; static HSWITCH hSwitch = 0 ; /* switching between windows */ static SWCNTRL swGnu ; static BOOL bLineTypes = FALSE ; // true if use dashed linetypes BOOL bWideLines ; static BOOL bColours = TRUE ; static BOOL bShellPos = FALSE ; static BOOL bPlotPos = FALSE ; static BOOL bPopFront = TRUE ; static BOOL bNewFont = FALSE ; static BOOL bHorz = TRUE ; static ULONG ulPlotPos[4] ; static ULONG ulShellPos[4] ; static PAUSEDATA pausedata = {sizeof(PAUSEDATA), NULL, NULL} ; static char szFontNameSize[FONTBUF] ; static PRQINFO3 infPrinter = { "" } ; static QPRINT qPrintData = { sizeof(QPRINT), 0.0, 0.0, 1.0, 1.0, 0, "", "", &infPrinter, 0, NULL } ; //static HEV semStartSeq ; /* semaphore to start things in right sequence */ static HEV semPause ; static HMTX semHpsAccess ; static ULONG ulPauseReply = 1 ; static ULONG ulPauseMode = PAUSE_DLG ; static HWND hSysMenu ; /* stuff for screen-draw thread control */ static BOOL bExist ; //static HEV semDrawDone ; /* thread control */ static TID tidDraw, tidSpawn ; /* font data */ static int lSupOffset = 0 ; static int lSubOffset = 0 ; static int lBaseSupOffset = 0 ; static int lBaseSubOffset = 0 ; static int lCharWidth = 217 ; static int lCharHeight = 465 ; /*==== f u n c t i o n s =====================================================*/ int DoPrint( HWND ) ; HBITMAP CopyToBitmap( HPS ) ; HMF CopyToMetaFile( HPS ) ; MRESULT WmClientCmdProc( HWND , ULONG, MPARAM, MPARAM ) ; void ChangeCheck( HWND, USHORT, USHORT ) ; BOOL QueryIni( HAB ) ; static void SaveIni( HWND ) ; static void ThreadDraw( void* ) ; static void DoPaint( HWND, HPS ) ; static void Display( HPS ) ; void SelectFont( HPS, char * ); void SwapFont( HPS, char * ); static void CopyToClipBrd( HWND ) ; static void ReadGnu( void* ) ; static void EditLineTypes( HWND, HPS, BOOL ) ; static void EditCharCell( HPS, SIZEF* ) ; static HPS InitScreenPS( void ) ; static int BufRead( HFILE, void*, int, PULONG ) ; int GetNewFont( HWND, HPS ) ; void SigHandler( int ) ; void FontExpand( char * ) ; static char *ParseText(HPS, char *, BOOL, char *, int, int, BOOL, BOOL ) ; static void CharStringAt(HPS, int, int, int, char *) ; static int QueryTextBox( HPS, int, char * ) ; static void LMove( HPS hps, POINTL *p ) ; static void LLine( HPS hps, POINTL *p ) ; static void LType( int iType ) ; /*==== c o d e ===============================================================*/ MRESULT EXPENTRY DisplayClientWndProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2) /* ** Window proc for main window ** -- passes most stuff to active child window via WmClientCmdProc ** -- passes DDE messages to DDEProc */ { static BOOL bSw = FALSE ; static BOOL bFirst = TRUE ; static RECTL rectlPaint = { 0, 0, 0, 0 } ; static int iPaintCount = 0 ; static int firstcall = 1 ; switch (message) { case WM_CREATE: { HDC hdcScreen ; SIZEL sizlPage ; // set initial values ChangeCheck( hWnd, IDM_LINES_THICK, bWideLines?IDM_LINES_THICK:0 ) ; ChangeCheck( hWnd, IDM_LINES_SOLID, bLineTypes?0:IDM_LINES_SOLID ) ; ChangeCheck( hWnd, IDM_COLOURS, bColours?IDM_COLOURS:0 ) ; ChangeCheck( hWnd, IDM_FRONT, bPopFront?IDM_FRONT:0 ) ; // disable close from system menu (close only from gnuplot) hApp = WinQueryWindow( hWnd, QW_PARENT ) ; /* temporary assignment.. */ hSysMenu = WinWindowFromID( hApp, FID_SYSMENU ) ; // setup semaphores // DosCreateEventSem( NULL, &semDrawDone, 0L, 0L ) ; // DosCreateEventSem( NULL, &semStartSeq, 0L, 0L ) ; DosCreateEventSem( NULL, &semPause, 0L, 0L ) ; DosCreateMutexSem( NULL, &semHpsAccess, 0L, 1L ) ; bExist = TRUE ; // create a dc and hps to draw on the screen hdcScreen = WinOpenWindowDC( hWnd ) ; sizlPage.cx = 0 ; sizlPage.cy = 0 ; sizlPage.cx = 19500 ; sizlPage.cy = 12500 ; hpsScreen = GpiCreatePS( hab, hdcScreen, &sizlPage, PU_HIMETRIC|GPIT_NORMAL|GPIA_ASSOC) ; // spawn server for GNUPLOT ... tidSpawn = _beginthread( ReadGnu, NULL, 32768, NULL ) ; } break ; case WM_GPSTART: // get details of command-line window hSwitch = WinQuerySwitchHandle( 0, ppidGnu ) ; WinQuerySwitchEntry( hSwitch, &swGnu ) ; if( firstcall ) { // set size of this window WinSetWindowPos( WinQueryWindow( hWnd, QW_PARENT ), bPopFront?HWND_TOP:swGnu.hwnd, ulShellPos[0], ulShellPos[1], ulShellPos[2], ulShellPos[3], bShellPos?(bPopFront?SWP_SIZE|SWP_MOVE|SWP_SHOW|SWP_ACTIVATE :SWP_SIZE|SWP_MOVE|SWP_SHOW|SWP_ZORDER) :(bPopFront?SWP_SHOW|SWP_ACTIVATE:SWP_SHOW|SWP_ZORDER) ) ; signal( SIGTERM, SigHandler ) ; firstcall = 0 ; } if( !bPopFront ) WinSwitchToProgram( hSwitch ) ; // DosPostEventSem( semDrawDone ) ; DosReleaseMutexSem( semHpsAccess ) ; return 0 ; case WM_COMMAND: return WmClientCmdProc( hWnd , message , mp1 , mp2 ) ; case WM_CHAR: /* If the user types a command in the driver window, we route it to the gnuplot window and switch that to the front. Doesn't work for full-screen sessions, though (but does switch). */ { USHORT usFlag ; usFlag = SHORT1FROMMP( mp1 ) ; if( !(usFlag & (KC_KEYUP|KC_ALT|KC_CTRL)) ) { USHORT uc = SHORT1FROMMP( mp2 ) ; HWND hw = WinQueryWindow( swGnu.hwnd, QW_BOTTOM ) ; WinSetFocus( HWND_DESKTOP, hw ) ; WinSendMsg( hw, message, MPFROM2SHORT((USHORT)(KC_SCANCODE), 1), MPFROMSHORT(uc) ) ; WinSwitchToProgram( hSwitch ) ; } } break ; case WM_DESTROY: if( WinSendMsg( hWnd, WM_USER_PRINT_QBUSY, 0L, 0L ) != 0L ) { WinMessageBox( HWND_DESKTOP, hWnd, "Still printing - not closed", APP_NAME, 0, MB_OK | MB_ICONEXCLAMATION ) ; return 0L ; } return (WinDefWindowProc(hWnd, message, mp1, mp2)); case WM_PAINT: { ULONG ulCount ; PID pid; TID tid; HPS hps_tmp; RECTL rectl_tmp; DosQueryMutexSem( semHpsAccess, &pid, &tid, &ulCount ) ; if (( ulCount > 0 ) && (tid != tidDraw)) { /* simple repaint while building plot or metafile */ /* use temporary PS */ hps_tmp = WinBeginPaint(hWnd,0,&rectl_tmp ); WinFillRect(hps_tmp,&rectl_tmp,CLR_BACKGROUND); WinEndPaint(hps_tmp); /* add dirty rectangle to saved rectangle */ /* to be repainted when PS is available again */ WinUnionRect(hab,&rectlPaint,&rectl_tmp,&rectlPaint); iPaintCount ++ ; break ; } WinInvalidateRect( hWnd, &rectlPaint, TRUE ) ; DoPaint( hWnd, hpsScreen ) ; WinSetRectEmpty( hab, &rectlPaint ) ; } break ; case WM_SIZE : { WinInvalidateRect( hWnd, NULL, TRUE ) ; } break ; case WM_PRESPARAMCHANGED: { char *pp ; ULONG ulID ; pp = malloc(FONTBUF) ; if( WinQueryPresParam( hWnd, PP_FONTNAMESIZE, 0, &ulID, FONTBUF, pp, QPF_NOINHERIT ) != 0L ) { strcpy( szFontNameSize, pp ) ; bNewFont = TRUE ; WinInvalidateRect( hWnd, NULL, TRUE ) ; } free(pp) ; } break ; case WM_USER_PRINT_BEGIN: case WM_USER_PRINT_OK : case WM_USER_DEV_ERROR : case WM_USER_PRINT_ERROR : case WM_USER_PRINT_QBUSY : return( PrintCmdProc( hWnd, message, mp1, mp2 ) ) ; case WM_GNUPLOT: // display the plot if( bPopFront ) WinSetWindowPos( hwndFrame, HWND_TOP, 0,0,0,0, SWP_ACTIVATE|SWP_ZORDER ) ; if( iPaintCount > 0 ) { /* if outstanding paint messages, repaint */ WinInvalidateRect( hWnd, &rectlPaint, TRUE ) ; iPaintCount = 0 ; } return 0L ; case WM_PAUSEPLOT: /* put pause message on screen, or enable 'continue' button */ if( ulPauseMode == PAUSE_DLG ) { pausedata.pszMessage = (char*)mp1 ; WinLoadDlg( HWND_DESKTOP, hWnd, (PFNWP)PauseMsgDlgProc, 0L, IDD_PAUSEBOX, &pausedata ) ; } else { WinEnableMenuItem( WinWindowFromID( WinQueryWindow( hWnd, QW_PARENT ), FID_MENU ), IDM_CONTINUE, TRUE ) ; } return 0L ; case WM_PAUSEEND: /* resume plotting */ ulPauseReply = (ULONG) mp1 ; DosPostEventSem( semPause ) ; return 0L ; default: /* Passes it on if unproccessed */ return (WinDefWindowProc(hWnd, message, mp1, mp2)); } return (NULL); } MRESULT WmClientCmdProc(HWND hWnd, ULONG message, MPARAM mp1, MPARAM mp2) /* ** Handle client window command (menu) messages */ { extern HWND hApp ; static ulPauseItem = IDM_PAUSEDLG ; switch( (USHORT) SHORT1FROMMP( mp1 ) ) { case IDM_ABOUT : /* show the 'About' box */ WinDlgBox( HWND_DESKTOP, hWnd , (PFNWP)About , 0L, ID_ABOUT, NULL ) ; break ; case IDM_GPLOTINF: /* view gnuplot.inf */ { char path[256] ; char *p ; strcpy( path, "start view " ) ; if( (p=getenv("GNUPLOT")) != NULL ) { strcat( path, p ) ; strcat( path, "/" ) ; } strcat( path, "gnuplot" ) ; system( path ) ; } break ; case IDM_PRINT : /* print plot */ if( SetupPrinter( hWnd, &qPrintData ) ) { WinPostMsg( hWnd, WM_USER_PRINT_BEGIN, (MPARAM) &qPrintData, (MPARAM) hpsScreen ) ; } break ; case IDM_PRINTSETUP : /* select printer */ WinDlgBox( HWND_DESKTOP, hWnd , (PFNWP)QPrintersDlgProc, 0L, IDD_QUERYPRINT, qPrintData.szPrinterName ) ; break ; case IDM_LINES_THICK: // change line setting bWideLines = !bWideLines ; ChangeCheck( hWnd, IDM_LINES_THICK, bWideLines?IDM_LINES_THICK:0 ) ; WinInvalidateRect( hWnd, NULL, TRUE ) ; break ; case IDM_LINES_SOLID: // change line setting bLineTypes = !bLineTypes ; ChangeCheck( hWnd, IDM_LINES_SOLID, bLineTypes?0:IDM_LINES_SOLID ) ; EditLineTypes( hWnd, hpsScreen, bLineTypes ) ; WinInvalidateRect( hWnd, NULL, TRUE ) ; break ; case IDM_COLOURS: // change colour setting bColours = !bColours ; ChangeCheck( hWnd, IDM_COLOURS, bColours?IDM_COLOURS:0 ) ; WinInvalidateRect( hWnd, NULL, TRUE ) ; break ; case IDM_FRONT: /* toggle z-order forcing */ bPopFront = !bPopFront ; ChangeCheck( hWnd, IDM_FRONT, bPopFront?IDM_FRONT:0 ) ; break ; case IDM_FONTS: if( GetNewFont( hWnd, hpsScreen ) ) { bNewFont = TRUE ; WinInvalidateRect( hWnd, NULL, TRUE ) ; } break ; case IDM_SAVE : SaveIni( hWnd ) ; break ; case IDM_COPY : /* copy to clipboard */ if( WinOpenClipbrd( hab ) ) { CopyToClipBrd( hWnd ) ; } else { WinMessageBox( HWND_DESKTOP, hWnd, "Can't open clipboard", APP_NAME, 0, MB_OK | MB_ICONEXCLAMATION ) ; } break ; case IDM_CLEARCLIP : /* clear clipboard */ if( WinOpenClipbrd( hab ) ) { WinEmptyClipbrd( hab ) ; WinCloseClipbrd( hab ) ; } else { WinMessageBox( HWND_DESKTOP, hWnd, "Can't open clipboard", APP_NAME, 0, MB_OK | MB_ICONEXCLAMATION ) ; } break ; case IDM_COMMAND: /* go back to GNUPLOT command window */ WinSwitchToProgram( hSwitch ) ; break ; case IDM_CONTINUE: WinPostMsg( hWnd, WM_PAUSEEND, (MPARAM)1L, (MPARAM)0L ) ; WinEnableMenuItem( WinWindowFromID( WinQueryWindow( hWnd, QW_PARENT ), FID_MENU ), IDM_CONTINUE, FALSE ) ; break ; case IDM_PAUSEGNU: /* gnuplot handles pause */ ChangeCheck( hWnd, ulPauseItem, IDM_PAUSEGNU ) ; ulPauseItem = IDM_PAUSEGNU ; ulPauseMode = PAUSE_GNU ; break ; case IDM_PAUSEDLG: /* pause message in dlg box */ ChangeCheck( hWnd, ulPauseItem, IDM_PAUSEDLG ) ; ulPauseItem = IDM_PAUSEDLG ; ulPauseMode = PAUSE_DLG ; break ; case IDM_PAUSEBTN: /* pause uses menu button, no message */ ChangeCheck( hWnd, ulPauseItem, IDM_PAUSEBTN ) ; ulPauseItem = IDM_PAUSEBTN ; ulPauseMode = PAUSE_BTN ; break ; case IDM_HELPFORHELP: WinSendMsg(WinQueryHelpInstance(hWnd), HM_DISPLAY_HELP, 0L, 0L ) ; return 0L ; case IDM_EXTENDEDHELP: WinSendMsg(WinQueryHelpInstance(hWnd), HM_EXT_HELP, 0L, 0L); return 0L ; case IDM_KEYSHELP: WinSendMsg(WinQueryHelpInstance(hWnd), HM_KEYS_HELP, 0L, 0L); return 0L ; case IDM_HELPINDEX: WinSendMsg(WinQueryHelpInstance(hWnd), HM_HELP_INDEX, 0L, 0L); return 0L ; default : return WinDefWindowProc( hWnd, message, mp1, mp2 ) ; } return( NULL ) ; } void ChangeCheck( HWND hWnd , USHORT wItem1 , USHORT wItem2 ) /* ** Utility function: ** ** move check mark from menu item 1 to item 2 */ { HWND hMenu ; hMenu = WinWindowFromID( WinQueryWindow( hWnd, QW_PARENT ), FID_MENU ) ; if( wItem1 != 0 ) WinSendMsg( hMenu, MM_SETITEMATTR, MPFROM2SHORT( wItem1, TRUE ), MPFROM2SHORT( MIA_CHECKED, 0 ) ) ; if( wItem2 != 0 ) WinSendMsg( hMenu, MM_SETITEMATTR, MPFROM2SHORT( wItem2, TRUE ), MPFROM2SHORT( MIA_CHECKED, MIA_CHECKED ) ) ; } static void CopyToClipBrd( HWND hWnd ) /* ** Copy window to clipboard as bitmap. */ { HAB hab ; HBITMAP hbm ; HMF hmf ; hab = WinQueryAnchorBlock( hWnd ) ; WinEmptyClipbrd( hab ) ; hbm = CopyToBitmap( hpsScreen ) ; WinSetClipbrdData( hab, (ULONG) hbm, CF_BITMAP, CFI_HANDLE) ; hmf = CopyToMetaFile( hpsScreen ) ; WinSetClipbrdData( hab, (ULONG) hmf, CF_METAFILE, CFI_HANDLE) ; WinCloseClipbrd( hab ) ; } HBITMAP CopyToBitmap( HPS hps ) /* ** Copy ps to a bitmap. */ { HPS hpsMem ; HWND hwnd ; HAB hab ; PSZ psz[4] = {NULL,"Display",NULL,NULL} ; HDC hdcMem, hdcScr ; SIZEL sizel ; BITMAPINFOHEADER2 bmp ; PBITMAPINFO2 pbmi ; HBITMAP hbm ; BYTE abBmp[80] ; LONG alData[2] ; RECTL rectl ; POINTL aptl[6] ; HMF hmf ; hdcScr = GpiQueryDevice( hps ) ; hwnd = WinWindowFromDC( hdcScr ) ; hab = WinQueryAnchorBlock( hwnd ) ; hdcMem = DevOpenDC( hab, OD_MEMORY, "*", 4L, (PDEVOPENDATA) psz, hdcScr ) ; sizel.cx = 0/*GNUPAGE*/ ; sizel.cy = 0/*GNUPAGE*/ ; hpsMem = GpiCreatePS( hab, hdcMem, &sizel, PU_PELS|GPIA_ASSOC|GPIT_MICRO ) ; GpiQueryDeviceBitmapFormats( hpsMem, 2L, alData ) ; WinQueryWindowRect( hwnd, &rectl ) ; memset( &bmp, 0, sizeof(bmp) ) ; bmp.cbFix = (ULONG) sizeof( bmp ) ; bmp.cx = (SHORT) (rectl.xRight-rectl.xLeft) ; bmp.cy = (SHORT) (rectl.yTop-rectl.yBottom) ; bmp.cPlanes = alData[0] ; bmp.cBitCount = alData[1] ; hbm = GpiCreateBitmap( hpsMem, &bmp, 0, NULL, NULL ) ; GpiSetBitmap( hpsMem, hbm ) ; aptl[0].x = 0 ; aptl[0].y = 0 ; aptl[1].x = (LONG)bmp.cx ; aptl[1].y = (LONG)bmp.cy ; aptl[2].x = 0 ; aptl[2].y = 0 ; GpiBitBlt( hpsMem, hps, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE ) ; GpiDestroyPS( hpsMem ) ; DevCloseDC( hdcMem ) ; return hbm ; } HMF CopyToMetaFile( HPS hps ) /* ** Copy ps to a mteafile. */ { HDC hdcMF, hdcOld ; HAB hab ; HWND hwnd ; PSZ psz[4] = {NULL,"Display",NULL,NULL} ; HMF hmf ; hdcOld = GpiQueryDevice( hps ) ; hwnd = WinWindowFromDC( hdcOld ) ; hab = WinQueryAnchorBlock( hwnd ) ; hdcMF = DevOpenDC( hab, OD_METAFILE, "*", 4L, psz, hdcOld ) ; DosRequestMutexSem( semHpsAccess, (ULONG) SEM_INDEFINITE_WAIT ) ; GpiSetDrawingMode( hps, DM_DRAW ) ; GpiAssociate( hps, 0 ) ; GpiAssociate( hps, hdcMF ) ; ScalePS( hps ) ; GpiDrawChain( hps ) ; GpiAssociate( hps, 0 ) ; GpiAssociate( hps, hdcOld ) ; DosReleaseMutexSem( semHpsAccess ) ; hmf = DevCloseDC( hdcMF ) ; return hmf ; } BOOL QueryIni( HAB hab ) /* ** Query INI file */ { BOOL bPos, bData, bSwp ; ULONG ulOpts[5] ; HINI hini ; ULONG ulCB ; char *p ; static SWP pauseswp ; // read gnuplot ini file hini = PrfOpenProfile( hab, szIniFile ) ; ulCB = sizeof( ulShellPos ) ; bPos = PrfQueryProfileData( hini, APP_NAME, INISHELLPOS, &ulShellPos, &ulCB ) ; ulCB = sizeof( SWP ) ; bSwp = PrfQueryProfileData( hini, APP_NAME, INIPAUSEPOS, &pauseswp, &ulCB ) ; if( bSwp ) pausedata.pswp = &pauseswp ; ulCB = sizeof( ulOpts ) ; bData = PrfQueryProfileData( hini, APP_NAME, INIOPTS, &ulOpts, &ulCB ) ; if( bData ) { bLineTypes = (BOOL)ulOpts[0] ; bWideLines = (BOOL)ulOpts[1] ; bColours = (BOOL)ulOpts[2] ; ulPauseMode = ulOpts[3] ; bPopFront = (BOOL)ulOpts[4] ; } else { bLineTypes = FALSE ; /* default values */ /* bWideLines = FALSE ; */ bColours = TRUE ; bPopFront = TRUE ; ulPauseMode = 1 ; } ulCB = 4*sizeof(float) ; PrfQueryProfileData( hini, APP_NAME, INIFRAC, &qPrintData.xsize, &ulCB ) ; if( PrfQueryProfileSize( hini, APP_NAME, INIPRDRIV, &ulCB ) ) { PDRIVDATA pdriv = (PDRIVDATA) malloc( ulCB ) ; if( pdriv != NULL ) { PrfQueryProfileData( hini, APP_NAME, INIPRDRIV, pdriv, &ulCB ) ; qPrintData.pdriv = pdriv ; qPrintData.cbpdriv = ulCB ; } } PrfQueryProfileString( hini, APP_NAME, INIPRPR, "", qPrintData.szPrinterName, (long) sizeof qPrintData.szPrinterName ) ; PrfQueryProfileString( hini, APP_NAME, INIFONT, INITIAL_FONT, szFontNameSize, FONTBUF ) ; ulCB = sizeof( ulOpts ) ; bData = PrfQueryProfileData( hini, APP_NAME, INICHAR, &ulOpts, &ulCB ) ; if( bData ) { lCharWidth = ulOpts[0] ; lCharHeight = ulOpts[1] ; } else { lCharWidth = 217 ; lCharHeight = 465 ; } PrfCloseProfile( hini ) ; if( qPrintData.szPrinterName[0] == '\0' ) { // get default printer name PrfQueryProfileString( HINI_PROFILE, "PM_SPOOLER", "PRINTER", ";", qPrintData.szPrinterName, (long) sizeof qPrintData.szPrinterName ) ; if( (p=strchr( qPrintData.szPrinterName, ';' )) != NULL ) *p = '\0' ; } bShellPos = bPos ; return bPos ; } static void SaveIni( HWND hWnd ) /* ** save data in ini file */ { SWP swp ; HINI hini ; ULONG ulOpts[5] ; HFILE hfile ; ULONG ulAct ; ERRORID errid ; char achErr[64] ; HAB hab ; hab = WinQueryAnchorBlock( hWnd ) ; hini = PrfOpenProfile( hab, szIniFile ) ; if( hini != NULLHANDLE ) { WinQueryWindowPos( hwndFrame, &swp ) ; ulPlotPos[0] = swp.x ; ulPlotPos[1] = swp.y ; ulPlotPos[2] = swp.cx ; ulPlotPos[3] = swp.cy ; PrfWriteProfileData( hini, APP_NAME, INISHELLPOS, &ulPlotPos, sizeof(ulPlotPos) ) ; if( pausedata.pswp != NULL ) PrfWriteProfileData( hini, APP_NAME, INIPAUSEPOS, pausedata.pswp, sizeof(SWP) ) ; ulOpts[0] = (ULONG)bLineTypes ; ulOpts[1] = (ULONG)bWideLines ; ulOpts[2] = (ULONG)bColours ; ulOpts[3] = ulPauseMode ; ulOpts[4] = (ULONG)bPopFront ; PrfWriteProfileData( hini, APP_NAME, INIOPTS, &ulOpts, sizeof(ulOpts) ) ; PrfWriteProfileData( hini, APP_NAME, INIFRAC, &qPrintData.xsize, 4*sizeof(float) ) ; if( qPrintData.pdriv != NULL ) PrfWriteProfileData( hini, APP_NAME, INIPRDRIV, qPrintData.pdriv, qPrintData.cbpdriv ) ; PrfWriteProfileString( hini, APP_NAME, INIPRPR, qPrintData.szPrinterName[0] == '\0'? NULL: qPrintData.szPrinterName ) ; PrfWriteProfileString( hini, APP_NAME, INIFONT, szFontNameSize ) ; ulOpts[0] = (ULONG)lCharWidth ; ulOpts[1] = (ULONG)lCharHeight ; PrfWriteProfileData( hini, APP_NAME, INICHAR, &ulOpts, sizeof(ulOpts) ) ; PrfCloseProfile( hini ) ; } else { WinMessageBox( HWND_DESKTOP, HWND_DESKTOP, "Can't write ini file", APP_NAME, 0, MB_OK | MB_ICONEXCLAMATION ) ; } } static void DoPaint( HWND hWnd, HPS hps ) /* ** Paint the screen with current data */ { ULONG ulCount ; static RECTL rectl ; if( tidDraw != 0 ) { /* already drawing - stop it; include the rectl now being drawn in, in the update region; and return without calling beginpaint so that the paint message is resent */ GpiSetStopDraw( hpsScreen, SDW_ON ) ; DosSleep(1) ; WinInvalidateRect( hWnd, &rectl, TRUE ) ; return ; } /* winbeginpaint here, so paint message is not resent when we return, then spawn a thread to do the drawing */ WinBeginPaint( hWnd, hps, &rectl ) ; //rl tidDraw = _beginthread( ThreadDraw, NULL, 32768, NULL ) ; } static void ThreadDraw( void* arg ) /* ** Thread to draw plot on screen */ { HAB hab ; hab = WinInitialize( 0 ) ; InitScreenPS() ; DosRequestMutexSem( semHpsAccess, (ULONG) SEM_INDEFINITE_WAIT ) ; ScalePS( hpsScreen ) ; GpiSetStopDraw( hpsScreen, SDW_OFF ) ; GpiSetDrawingMode( hpsScreen, DM_DRAW ) ; GpiDrawChain( hpsScreen ) ; WinEndPaint( hpsScreen ) ; DosReleaseMutexSem( semHpsAccess ) ; WinTerminate( hab ) ; tidDraw = 0 ; } HPS InitScreenPS() /* ** Initialise the screen ps for drawing */ { RECTL rectClient ; int nColour = 0 ; GpiResetPS( hpsScreen, GRES_ATTRS ) ; GpiErase(hpsScreen); WinQueryWindowRect( hApp, (PRECTL)&rectClient ) ; { double ratio = 1.560 ; double xs = rectClient.xRight - rectClient.xLeft ; double ys = rectClient.yTop - rectClient.yBottom ; if( ys > xs/ratio ) { /* reduce ys to fit */ rectClient.yTop = rectClient.yBottom + (int)(xs/ratio) ; } else if( ys < xs/ratio ) { /* reduce xs to fit */ rectClient.xRight = rectClient.xLeft + (int)(ys*ratio) ; } } GpiSetPageViewport( hpsScreen, &rectClient ) ; if( !bColours ) { int i ; for( i=0; i<8; i++ ) alColourTable[i] = 0 ; for( i=8; i<16; i++ ) alColourTable[i] = 0 ; alColourTable[0] = 0xFFFFFF ; nColour = 16 ; } GpiCreateLogColorTable( hpsScreen, LCOL_RESET, LCOLF_CONSECRGB, 0, nColour, alColourTable ) ; return hpsScreen ; } enum JUSTIFY { LEFT, CENTRE, RIGHT } jmode; short ScalePS( HPS hps ) /* ** Get a font to use ** Scale the plot area to world coords for subsequent plotting */ { RECTL rectView ; SelectFont( hps, szFontNameSize ) ; return 0 ; } static SIZEF sizBaseSubSup ; static SIZEF sizCurSubSup ; static SIZEF sizCurFont ; static long lVOffset = 0 ; static SIZEF sizBaseFont ; static struct _ft { char *name ; LONG lcid ; } tabFont[256] = {{NULL,0L}, {NULL}}; void SelectFont( HPS hps, char *szFontNameSize ) /* ** Select a named and sized outline (adobe) font */ { HDC hdc ; FATTRS fat ; LONG xDeviceRes, yDeviceRes ; POINTL ptlFont ; SIZEF sizfx ; static LONG lcid = 0L ; static char *szFontName ; static short shPointSize ; sscanf( szFontNameSize, "%hd", &shPointSize ) ; szFontName = strchr( szFontNameSize, '.' ) + 1 ; fat.usRecordLength = sizeof fat ; fat.fsSelection = 0 ; fat.lMatch = 0 ; fat.idRegistry = 0 ; fat.usCodePage = 0 ; //GpiQueryCp (hps) ; fat.lMaxBaselineExt = 0 ; fat.lAveCharWidth = 0 ; fat.fsType = 0 ; fat.fsFontUse = FATTR_FONTUSE_OUTLINE | FATTR_FONTUSE_TRANSFORMABLE ; strcpy (fat.szFacename, szFontName) ; if(tabFont[0].name !=NULL) free( tabFont[0].name ) ; tabFont[0].name = strdup( szFontName ) ; tabFont[0].lcid = 10L ; lcid = GpiQueryCharSet( hps ) ; if( lcid != 10L ) lcid = 10L ; else { GpiSetCharSet( hps, 0L) ; GpiDeleteSetId( hps, lcid ) ; } GpiCreateLogFont (hps, NULL, lcid, &fat) ; GpiSetCharSet( hps, lcid ) ; hdc = GpiQueryDevice (hps) ; DevQueryCaps (hdc, CAPS_HORIZONTAL_RESOLUTION, 1L, &xDeviceRes) ; DevQueryCaps (hdc, CAPS_VERTICAL_RESOLUTION, 1L, &yDeviceRes) ; // Find desired font size in pixels ptlFont.x = 2540L * (long)shPointSize / 72L ; ptlFont.y = 2540L * (long)shPointSize / 72L ; // Set the character box sizfx.cx = MAKEFIXED (ptlFont.x, 0) ; sizfx.cy = MAKEFIXED (ptlFont.y, 0) ; lVOffset = ptlFont.y ; sizBaseFont = sizfx ; GpiSetCharBox (hps, &sizfx) ; // set up some useful globals { FONTMETRICS fm ; GpiQueryFontMetrics( hps, sizeof(FONTMETRICS), &fm ) ; lBaseSubOffset = -fm.lSubscriptYOffset ; lBaseSupOffset = fm.lSuperscriptYOffset ; lSubOffset = lBaseSubOffset ; lSupOffset = lBaseSupOffset ; lCharHeight = fm.lMaxAscender*1.2 ; lCharWidth = fm.lAveCharWidth ; sizBaseSubSup.cx = MAKEFIXED( ptlFont.x*0.7, 0 ) ; sizBaseSubSup.cy = MAKEFIXED( ptlFont.y*0.7, 0 ) ; } sizCurFont = sizBaseFont ; sizCurSubSup = sizBaseSubSup ; if( bNewFont ) { // EditCharCell( hps, &sizfx ) ; bNewFont = FALSE ; } } void SwapFont( HPS hps, char *szFNS ) /* ** Select a named and sized outline (adobe) font */ { HDC hdc ; FATTRS fat ; LONG xDeviceRes, yDeviceRes ; POINTL ptlFont ; SIZEF sizfx ; static LONG lcid = 0L ; static int itab = 1 ; static char *szFontName ; static short shPointSize ; if( szFNS == NULL ) { /* restore base font */ sizCurFont = sizBaseFont ; sizCurSubSup = sizBaseSubSup ; lSubOffset = lBaseSubOffset ; lSupOffset = lBaseSupOffset ; GpiSetCharSet( hps, 10 ) ; GpiSetCharBox (hps, &sizBaseFont) ; } else { sscanf( szFNS, "%hd", &shPointSize ) ; szFontName = strchr( szFNS, '.' ) + 1 ; { int i ; lcid = 0 ; for(i=0;i 0 ){ /* get pause text */ DosEnterCritSec() ; szPauseText = malloc( len*sizeof(int) ) ; DosExitCritSec() ; BufRead(hRead,szPauseText, len*sizeof(int), &cbR) ; } if( ulPauseMode != PAUSE_GNU ) { /* pause and wait for semaphore to be cleared */ DosResetEventSem( semPause, &ulPause ) ; WinPostMsg( hApp, WM_PAUSEPLOT, (MPARAM) szPauseText, 0L ) ; DosWaitEventSem( semPause, SEM_INDEFINITE_WAIT ) ; } else { /* gnuplot handles pause */ ulPauseReply = 2 ; } DosEnterCritSec() ; if( szPauseText != NULL ) free( szPauseText ) ; szPauseText = NULL ; DosExitCritSec() ; /* reply to gnuplot so it can continue */ DosWrite( hRead, &ulPauseReply, sizeof(int), &cbR ) ; } break ; case 'T' : /* write text */ /* read x, y, len */ if( bPath ) { GpiEndPath( hps ) ; GpiStrokePath( hps, 1, 0 ) ; bPath = FALSE ; } { int x, y, len, sw ; char *str ; BufRead(hRead,&x, sizeof(int), &cbR) ; BufRead(hRead,&y, sizeof(int), &cbR) ; BufRead(hRead,&len, sizeof(int), &cbR) ; DosEnterCritSec() ; len = (len+sizeof(int)-1)/sizeof(int) ; if( len == 0 ) len = 1 ; //?? how about read str = malloc( len*sizeof(int) ) ; *str = '\0' ; DosExitCritSec() ; BufRead(hRead, str, len*sizeof(int), &cbR) ; lCurCol = GpiQueryColor( hps ) ; GpiSetColor( hps, CLR_BLACK ) ; sw = QueryTextBox( hps, strlen(str), str ) ; switch(jmode) { case LEFT: sw = 0; break; case CENTRE: sw = -sw/2; break; case RIGHT: sw = -sw; break; } if( bHorz ) { ptl.x = (LONG)(x+sw) ; ptl.y = (LONG)(y-lVOffset/4) ; } else { ptl.x = (LONG)x ; ptl.y = (LONG)(y+sw) ; } if(bEnhanced) CharStringAt( hps, ptl.x, ptl.y, strlen( str ) , str ) ; else GpiCharStringAt( hps, &ptl, strlen( str ), str ) ; GpiSetColor( hps, lCurCol ) ; DosEnterCritSec() ; free(str) ; DosExitCritSec() ; } break ; case 'J' : /* justify */ BufRead(hRead,&jmode, sizeof(int), &cbR) ; break ; case 'A' : /* text angle */ { int ta ; GRADIENTL grdl ; SIZEF sizHor, sizVer ; if( bPath ) { GpiEndPath( hps ) ; GpiStrokePath( hps, 1, 0 ) ; bPath = FALSE ; } BufRead(hRead,&ta, sizeof(int), &cbR) ; if( ta == 0 ) { grdl.x = 0L ; grdl.y = 0L ; GpiSetCharAngle( hps, &grdl ) ; if( !bHorz ) { bHorz = TRUE ; } } else if( ta == 1 ) { grdl.x = 0L ; grdl.y = 1L ; GpiSetCharAngle( hps, &grdl ) ; if( bHorz ) { bHorz = FALSE ; } } } break ; case 'L' : /* line type */ { int lt, col ; if( bPath ) { GpiEndPath( hps ) ; GpiStrokePath( hps, 1, 0 ) ; bPath = FALSE ; } BufRead(hRead,<, sizeof(int), &cbR) ; /* linetype = -2 axes, -1 border, 0 arrows, all to 0 */ col = lt ; if( lt == -2 ) GpiSetLineWidthGeom( hps, DEFLW*0.85 ) ; else if( lt == -1 ) GpiSetLineWidthGeom( hps, DEFLW*0.6 ) ; else GpiSetLineWidthGeom( hps, linewidth ) ; if( lt < 0 ) lt = 0 ; lt = (lt%8); col = (col+2)%16 ; GpiLabel( hps, lLineTypes[lt] ) ; lOldLine=lt ; LType( (bLineTypes||bBW)?lt:0 ) ; // GpiSetLineType( hps, (bLineTypes||bBW)?lLineTypes[lt]:lLineTypes[0] ) ; if( !bBW ) { /* maintain some flexibility here in case we don't want the model T option */ if( bColours ) GpiSetColor( hps, lCols[col] ) ; else GpiSetColor( hps, CLR_BLACK ) ; } } break ; case 'W' : /* line width */ { int lw ; if( bPath ) { GpiEndPath( hps ) ; GpiStrokePath( hps, 1, 0 ) ; bPath = FALSE ; } BufRead(hRead,&lw, sizeof(int), &cbR) ; GpiSetLineWidthGeom( hps, DEFLW*lw/100 ) ; linewidth = DEFLW*lw/100 ; } break ; case 'D' : /* points mode */ { int lt ; BufRead(hRead,<, sizeof(int), &cbR) ; /* 1: enter point mode, 0: exit */ if( bLineTypes || bBW ) { if( lt==1) LType(0) ; else LType( lOldLine ) ; // if( lt == 1 ) lOldLine = GpiSetLineType( hps, lLineTypes[0] ) ; // else GpiSetLineType( hps, lOldLine ) ; } // if( lt == 1 ) GpiSetLineWidthGeom( hps, 20 ) ; // else GpiSetLineWidthGeom( hps, 50 ) ; bDots = lt ; } break ; case 'F' : /* set font */ { int len ; char *str ; char font[FONTBUF] ; BufRead(hRead,&len, sizeof(int), &cbR) ; len = (len+sizeof(int)-1)/sizeof(int) ; if( len == 0 ) { SwapFont( hps, NULL ) ; } else { char *p ; str = malloc( len*sizeof(int) ) ; BufRead(hRead, str, len*sizeof(int), &cbR) ; p = strchr(str, ',') ; if( p==NULL ) strcpy( font, "14" ) ; else { *p = '\0' ; strcpy( font, p+1 ) ; } strcat( font,"." ) ; strcat( font, str ) ; free( str ) ; SwapFont( hps, font ) ; } } break ; case 'O' : /* set options */ { int len ; char *str ; BufRead(hRead,&len, sizeof(int), &cbR) ; len = (len+sizeof(int)-1)/sizeof(int) ; bWideLines = FALSE ; /* reset options */ bEnhanced = FALSE ; if( len > 0 ) { char *p ; p = str = malloc( len*sizeof(int) ) ; BufRead(hRead, str, len*sizeof(int), &cbR) ; while( (p=strchr(p,'-')) != NULL ) { ++p ; if( *p == 'w' ) bWideLines = TRUE ; if( *p == 'e' ) bEnhanced = TRUE ; ++p ; } free( str ) ; } } break ; default : /* should handle error */ break ; } } } exitserver: DosDisConnectNPipe( hRead ) ; WinPostMsg( hApp, WM_CLOSE, 0L, 0L ) ; } static void EditLineTypes( HWND hwnd, HPS hps, BOOL bDashed ) /* */ { int i, rc ; char buf[64] ; GpiSetDrawingMode( hps, DM_RETAIN ) ; GpiOpenSegment( hps, iSeg ) ; GpiSetEditMode( hps, SEGEM_REPLACE ) ; for( i=0; i<7; i++ ) { while( GpiSetElementPointerAtLabel( hps, lLineTypes[i] ) ) { GpiOffsetElementPointer( hps, 1 ) ; GpiSetLineType( hps, bDashed?lLineTypes[i]:lLineTypes[0] ) ; } GpiSetElementPointer( hps, 0 ) ; } GpiSetEditMode( hps, SEGEM_INSERT ) ; GpiCloseSegment( hps ) ; } static void EditCharCell( HPS hps, SIZEF *psize ) /* ** Edit segment to change char cell (font size) */ { int i ; LONG rl, rc ; SIZEF sizH, sizV ; char buf[64] ; int iVert = 0 ; sizH = *psize ; sizV.cx = sizH.cy ; sizV.cy = sizH.cx ; GpiSetDrawingMode( hps, DM_RETAIN ) ; GpiOpenSegment( hps, iSeg ) ; GpiSetEditMode( hps, SEGEM_REPLACE ) ; i=0 ; while( GpiSetElementPointer( hps, i ) ) { rc = GpiQueryElementPointer( hps) ; if( rc != i ) break ; rl = GpiQueryElementType( hps, &rc, 0, NULL ) ; if( rc == 0x34 || rc == 0x74 ) { LONG gdata ; GpiQueryElement( hps, 5, 4, (PBYTE)&gdata ) ; if( gdata == 0 ) iVert = 0 ; else iVert = 1 ; } else if( rc==0x33 || rc==0x03 ) GpiSetCharBox(hps, iVert?&sizV:&sizH ) ; ++i ; } GpiSetEditMode( hps, SEGEM_INSERT ) ; GpiCloseSegment( hps ) ; } static int BufRead( HFILE hfile, void *buf, int nBytes, ULONG *pcbR ) /* ** pull next plot command out of buffer read from GNUPLOT */ { ULONG ulR, ulRR ; int rc ; static char buffer[GNUBUF] ; static char *pbuffer = buffer+GNUBUF, *ebuffer = buffer+GNUBUF ; for( ; nBytes > 0 ; nBytes-- ) { if( pbuffer >= ebuffer ) { ulR = GNUBUF ; rc = DosRead( hfile, buffer, ulR, &ulRR ) ; if( rc != 0 ) return rc ; if( ulRR == 0 ) return 1 ; pbuffer = buffer ; ebuffer = pbuffer+ulRR ; } *(char*)buf++ = *pbuffer++ ; } return 0L ; } int GetNewFont( HWND hwnd, HPS hps ) /* ** Get a new font using standard font dialog */ { static FONTDLG pfdFontdlg; /* Font dialog info structure */ static int i1 =1 ; static int iSize ; char szPtList[64] ; HWND hwndFontDlg; /* Font dialog window handle */ char *p ; char szFamilyname[FACESIZE]; if( i1 ) { strcpy( pfdFontdlg.fAttrs.szFacename, strchr( szFontNameSize, '.' ) + 1 ) ; strcpy( szFamilyname, strchr( szFontNameSize, '.' ) + 1 ) ; sscanf( szFontNameSize, "%d", &iSize ) ; memset(&pfdFontdlg, 0, sizeof(FONTDLG)); pfdFontdlg.cbSize = sizeof(FONTDLG); pfdFontdlg.hpsScreen = hps; /* szFamilyname[0] = 0;*/ pfdFontdlg.pszFamilyname = szFamilyname; pfdFontdlg.usFamilyBufLen = FACESIZE; pfdFontdlg.fl = FNTS_HELPBUTTON | FNTS_CENTER | FNTS_VECTORONLY | FNTS_OWNERDRAWPREVIEW ; pfdFontdlg.clrFore = CLR_BLACK; pfdFontdlg.clrBack = CLR_WHITE; pfdFontdlg.usWeight = FWEIGHT_NORMAL ; //5 ; pfdFontdlg.fAttrs.usCodePage = 0; pfdFontdlg.fAttrs.usRecordLength = sizeof(FATTRS) ; } sprintf( szPtList, "%d 8 10 12 14 18 24", iSize ) ; pfdFontdlg.pszPtSizeList = szPtList ; pfdFontdlg.fxPointSize = MAKEFIXED(iSize,0); hwndFontDlg = WinFontDlg(HWND_DESKTOP, hwnd, &pfdFontdlg); if( i1 ) { pfdFontdlg.fl = FNTS_HELPBUTTON | FNTS_CENTER | FNTS_VECTORONLY | FNTS_INITFROMFATTRS ; i1=0; } if (hwndFontDlg && (pfdFontdlg.lReturn == DID_OK)) { iSize = FIXEDINT( pfdFontdlg.fxPointSize ) ; sprintf( szFontNameSize, "%d.%s", iSize, pfdFontdlg.fAttrs.szFacename ) ; return 1 ; } else return 0 ; } void SigHandler( int sig ) /* ** Handle termination signal to free up resources before ** termination. */ { if( sig == SIGTERM ) { if( bPersist ) { DosKillThread( tidSpawn ) ; signal( SIGTERM, SIG_ACK ) ; return ; } DosEnterCritSec() ; DosKillThread( tidSpawn ) ; DosKillThread( tidDraw ) ; DosExitCritSec() ; exit(0) ; } } /* disable debugging info */ #define TEXT_DEBUG(x) /* fprintf x; */ /* used in determining height of processed text */ //static float max_height, min_height; /* process a bit of string, and return the last character used. * p is start of string * brace is TRUE to keep processing to }, FALSE for do one character * fontname & fontsize are obvious * base is the current baseline * widthflag is TRUE if the width of this should count, * FALSE for zero width boxes * showflag is TRUE if this should be shown, * FALSE if it should not be shown (like TeX \phantom) */ static char *starttext = NULL ; static int textlen = 0 ; static BOOL bText = FALSE ; static int textwidth = 0 ; static POINTL ptlText ; static FILE *ff ; static char *ParseText(HPS hps, char *p, BOOL brace, char *fontname, int fontsize, int base, BOOL widthflag, BOOL showflag) { POINTL aptl[TXTBOX_COUNT] ; BOOL bChangeFont = FALSE ; TEXT_DEBUG((ff,"RECURSE WITH [%p] %s, %d %s %.1f %.1f %d %d\n", p, p, brace, fontname, fontsize, base, widthflag, showflag)) /* Start each recursion with a clean string */ //{FILE *ff;int i=textlen;ff=fopen("deb","a"); //for(i=0;i 0 ) { GpiQueryTextBox( hps, textlen, starttext, TXTBOX_COUNT, aptl ) ; if( bHorz ) textwidth += aptl[TXTBOX_BOTTOMRIGHT].x ; else textwidth += aptl[TXTBOX_BOTTOMRIGHT].y ; } if( bText ) { if(textlen > 0 ) { GpiCharStringAt( hps, &ptlText, textlen, starttext ) ; ptlText.x += aptl[TXTBOX_CONCAT].x + (bHorz?0:(-base)) ; ptlText.y += aptl[TXTBOX_CONCAT].y + (bHorz?base:0) ; } else { ptlText.x += (bHorz?0:(-base)) ; ptlText.y += (bHorz?base:0) ; } } textlen = 0 ; starttext = p ; if( fontname != NULL ) { char szFont[FONTBUF] ; sprintf(szFont, "%d.%s", fontsize, fontname ) ; SwapFont( hps, szFont ) ; bChangeFont = TRUE ; } if( base != 0 ) GpiSetCharBox( hps, &sizCurSubSup ) ; for ( ; *p; ++p) { int shift; switch (*p) { case '}' : /*{{{ deal with it*/ if (brace) { brace = 0 ; break ; } break; /*}}}*/ case '_' : case '^' : /*{{{ deal with super/sub script*/ shift = (*p == '^') ? lSupOffset : lSubOffset; p = ParseText(hps, p+1, FALSE, NULL/*fontname*/, fontsize*0.7, base+shift, widthflag, showflag); break; /*}}}*/ case '{' : { char *savepos=NULL, save=0; char *localfontname=fontname, ch; char localfontbuf[FONTBUF] ; int recode=1; int f=fontsize; BOOL bChangeFont = FALSE ; char *q=localfontbuf ; /*{{{ recurse (possibly with a new font) */ TEXT_DEBUG((ff,"Dealing with {\n")) if (*++p == '/') { /* then parse a fontname, optional fontsize */ while (*++p == ' '); if (*p=='-') { recode=0; while (*++p == ' '); } localfontname = p; while ((ch = *p) > ' ' && ch != '=') { localfontname=localfontbuf ; if(*p=='_') *q=' ' ; else *q=*p ; ++p;++q; } *q = '\0' ; FontExpand( localfontbuf ) ; save = *(savepos=p); if (ch == '=') { *p++ = '\0'; /*{{{ get optional font size*/ TEXT_DEBUG((ff,"Calling strtod(%s) ...", p)) f = strtod(p, &p); TEXT_DEBUG((ff,"Retured %.1f and %s\n", f, p)) if (!f) f = fontsize; TEXT_DEBUG((ff,"Font size %.1f\n", f)) /*}}}*/ } else { *p++ = '\0'; f = fontsize; } while (*p == ' ') ++p; if (! (*localfontname)) { localfontname = fontname; if( f != fontsize ) localfontname = strchr( szFontNameSize, '.' ) + 1 ; } } /*}}}*/ TEXT_DEBUG((ff,"Before recursing, we are at [%p] %s\n", p, p)) p = ParseText(hps,p, TRUE, localfontname, f, base, widthflag, showflag); TEXT_DEBUG((ff,"BACK WITH %s\n", p)); if (savepos) /* restore overwritten character */ *savepos = save; break; } case '@' : /*{{{ phantom box - prints next 'char', then restores currentpoint */ p = ParseText(hps,++p, FALSE, NULL/*fontname*/, fontsize, base, FALSE, showflag); break; /*}}}*/ case '&' : /*{{{ character skip - skips space equal to length of character(s) */ p = ParseText(hps,++p, FALSE, NULL/*fontname*/, fontsize, base, widthflag, FALSE); break; /*}}}*/ case '\\' : { char buffer[4] ; /* should need only one char.. */ char *q = buffer ; *q = '\0' ; ParseText(hps,q, FALSE, NULL, fontsize, base, widthflag, showflag); /*{{{ is it an escape */ /* special cases */ if (p[1]=='\\' || p[1]=='{' || p[1]=='}') { *q++=p[1] ; ++p ; } #if 0 else if (p[1] >= '0' && p[1] <= '7') { /* up to 3 octal digits */ int c = 0 ; c+=p[1]; ++p; if (p[1] >= '0' && p[1] <= '7') { c*=8; c+=p[1]; ++p; if (p[1] >= '0' && p[1] <= '7') { c*=8; c+=p[1]; ++p; } } *q++ = c ; break; } #endif *q = '\0' ; textlen = 1 ; starttext=buffer ; ParseText(hps,q, FALSE, NULL/*fontname*/, fontsize, base, widthflag, showflag); starttext=p+1 ; textlen = 0 ; /*}}}*/ } break ; default: ++textlen ; /*}}}*/ } /* like TeX, we only do one character in a recursion, unless it's * in braces */ if (!brace) break ; } if( textlen > 0 ) { GpiQueryTextBox( hps, textlen, starttext, TXTBOX_COUNT, aptl ) ; if( widthflag ) { if( bHorz ) textwidth += aptl[TXTBOX_BOTTOMRIGHT].x ; else textwidth += aptl[TXTBOX_BOTTOMRIGHT].y ; } } if( bText ) { if( textlen > 0 ) { if( showflag) GpiCharStringAt( hps, &ptlText, textlen, starttext ) ; if( widthflag ) { ptlText.x += aptl[TXTBOX_CONCAT].x ; ptlText.y += aptl[TXTBOX_CONCAT].y ; } } if( base != 0 ) { ptlText.x -= (bHorz?0:(-base)) ; ptlText.y -= (bHorz?base:0) ; } } if( bChangeFont ) { SwapFont( hps, NULL ) ; bChangeFont = FALSE ; } if( base != 0 ) GpiSetCharBox( hps, &sizBaseFont ) ; textlen = 0 ; starttext = p+1 ; return p; } static void CharStringAt(HPS hps, int x, int y, int len, char *str) { /* flush any pending graphics (all the XShow routines do this...) */ char *fontname ; int fontsize ; if (!strlen(str)) return; /* set up the globals */ ptlText.x = x ; ptlText.y = y ; bText = TRUE ; starttext = NULL ; textlen = 0 ; textwidth = 0 ; sscanf( szFontNameSize, "%d", &fontsize ) ; fontname = strchr( szFontNameSize, '.' ) + 1 ; while (*(str = ParseText(hps, str, TRUE, NULL, fontsize, 0.0, TRUE, TRUE))); } static int QueryTextBox( HPS hps, int len, char *str ) { char *fontname ; int fontsize ; if (!strlen(str)) return 0 ; /* set up the globals */ bText = FALSE ; starttext = NULL ; textlen = 0 ; textwidth = 0 ; sscanf( szFontNameSize, "%d", &fontsize ) ; fontname = strchr( szFontNameSize, '.' ) + 1 ; while (*(str = ParseText(hps, str, TRUE, NULL, fontsize, 0.0, TRUE, TRUE))); return textwidth ; } void FontExpand( char *name ) { if ( strcmp(name,"S")==0 ) strcpy( name, "Symbol Set" ) ; else if( strcmp(name,"H")==0 ) strcpy( name, "Helvetica" ) ; else if( strcmp(name,"T")==0 ) strcpy( name, "Times New Roman" ) ; else if( strcmp(name,"C")==0 ) strcpy( name, "Courier" ) ; } /*=======================================*/ static POINTL pCur ; static int iLinebegin = 1 ; static int iLtype = 0 ; static int iState = 0 ; static double togo = 0.0 ; static int iPatt[8][9] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 300, 200, -1, 0, 0, 0, 0, 0, 0 }, { 150, 150, -1, 0, 0, 0, 0, 0, 0 }, { 300, 200, 150, 200, -1, 0, 0, 0, 0 }, { 500, 200, -1, 0, 0, 0, 0, 0, 0 }, { 300, 200, 150, 200, 150, 200, -1, 0, 0 }, { 300, 200, 150, 200, 150, 200, 150, 200, -1 }, { 500, 200, 150, 200, -1, 0, 0, 0, 0 } } ; void LMove( HPS hps, POINTL *p ) { double ds, dx, dy ; if( iLinebegin ) { pCur = *p ; GpiMove( hps, p ) ; } else if( iLtype == 0 ) GpiMove( hps, p ) ; else { dx = p->x - pCur.x ; dy = p->y - pCur.y ; ds = sqrt( dx*dx + dy*dy ) ; dx /= ds ; dy /= ds ; while( ds > 0.0 ) { if( ds < togo ) { togo -= ds ; ds = 0.0 ; GpiMove( hps, p ) ; pCur = *p ; } else { POINTL pn ; pn.x = pCur.x + togo * dx ; pn.y = pCur.y + togo * dy ; GpiMove( hps, &pn ) ; pCur = pn ; ds -= togo ; iState++ ; if( iPatt[iLtype][iState] < 0 ) { togo = iPatt[iLtype][0] ; iState = 0 ; } else togo = iPatt[iLtype][iState] ; } } } } void LLine( HPS hps, POINTL *p ) { double ds, dx, dy ; if( iLinebegin ) iLinebegin = 0 ; if( iLtype == 0 ) GpiLine( hps, p ) ; else { dx = p->x - pCur.x ; dy = p->y - pCur.y ; ds = sqrt( dx*dx + dy*dy ) ; dx /= ds ; dy /= ds ; while( ds > 0.0 ) { if( ds < togo ) { togo -= ds ; ds = 0.0 ; if( iState&1 ) GpiMove( hps, p ) ; else GpiLine( hps, p ) ; pCur = *p ; } else { POINTL pn ; pn.x = pCur.x + togo * dx ; pn.y = pCur.y + togo * dy ; if( iState&1 ) GpiMove( hps, &pn ) ; else GpiLine( hps, &pn ) ; pCur = pn ; ds -= togo ; iState++ ; if( iPatt[iLtype][iState] < 0 ) { togo = iPatt[iLtype][0] ; iState = 0 ; } else togo = iPatt[iLtype][iState] ; } } } } void LType( int iType ) { iLinebegin = 1 ; if( iType > 7 ) iType = 0 ; iLtype = iType ; iState = 0 ; togo = iPatt[iLtype][0] ; }