/* * $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 #include #include #include #include #include #include #include #ifdef HAVE_MALLOC_H #include #endif #include #include #include #include #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 ) { 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 ) 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; inx0?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 () 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= 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= 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 \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