source: git/src/avenprcore.cc @ 79c239e

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since 79c239e was 79c239e, checked in by <nobody>, 19 years ago

This commit was manufactured by cvs2svn to create branch 'survex-1_1'.

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@2820 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/* avenprcore.c
2 * Printer independent parts of Survex printer drivers
3 * Copyright (C) 1993-2002,2004,2005 Olly Betts
4 * Copyright (C) 2004 Philip Underwood
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21/* FIXME provide more explanation when reporting errors in print.ini */
22
23#ifdef HAVE_CONFIG_H
24# include <config.h>
25#endif
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <limits.h>
30#include <math.h>
31#include <string.h>
32#include <ctype.h>
33#include <time.h>
34#include <float.h>
35
36#include "mainfrm.h"
37
38#include "useful.h"
39#include "filename.h"
40#include "message.h"
41#include "filelist.h"
42#include "img.h"
43#include "avenprcore.h"
44#include "debug.h"
45
46#if defined __WXMSW__ || defined __WXMAC__
47# include <wx/dcprint.h>
48#else
49# include <wx/dcps.h>
50#endif
51
52layout::layout(wxPageSetupDialogData* data)
53        : Labels(false), Crosses(false), Shots(true), Surface(false),
54          SkipBlank(false), Border(true), Cutlines(true), Raw(false),
55          title(NULL), datestamp(NULL), Scale(0), rot(0), tilt(0),
56          view(PLAN), scX(1), scY(1), xMin(0), xMax(-1), yMin(0), yMax(-1),
57          pagesX(1), pagesY(1), pages(1), xOrg(0), yOrg(0), footer(NULL)
58{
59    // Create a temporary wxPrinterDC/wxPostScriptDC so we can get access to
60    // the size of the printable area in mm to allow us to calculate how many
61    // pages will be needed.
62#if defined __WXMSW__ || defined __WXMAC__
63    wxPrinterDC pdc(data->GetPrintData());
64#else
65    wxPostScriptDC pdc(data->GetPrintData());
66#endif
67    int width, depth;
68    pdc.GetSizeMM(&width, &depth);
69    width -= data->GetMarginBottomRight().x + data->GetMarginTopLeft().x;
70    PaperWidth = width;
71    depth -= data->GetMarginBottomRight().y + data->GetMarginTopLeft().y;
72    // Allow for the 10mm footer.
73    PaperDepth = depth - 10;
74}
75
76void
77layout::pages_required() {
78    double image_dx, image_dy;
79    double image_centre_x, image_centre_y;
80    double paper_centre_x, paper_centre_y;
81
82    double allow = 21.0;
83    if (!Raw) allow += (view == EXTELEV ? 30.0 : 40.0);
84    double Sc = 1000 / Scale;
85    image_dx = (xMax - xMin) * Sc;
86    if (PaperWidth > 0.0) {
87        pagesX = (int)ceil((image_dx + 19.0) / PaperWidth);
88    } else {
89        /* paperwidth not fixed (eg window or roll printer/plotter) */
90        pagesX = 1;
91        PaperWidth = image_dx + 19.0;
92    }
93    paper_centre_x = (pagesX * PaperWidth) / 2;
94    image_centre_x = Sc * (xMax + xMin) / 2;
95    xOrg = paper_centre_x - image_centre_x;
96
97    image_dy = (yMax - yMin) * Sc;
98    if (PaperDepth > 0.0) {
99        pagesY = (int)ceil((image_dy + allow) / PaperDepth);
100    } else {
101        /* paperdepth not fixed (eg window or roll printer/plotter) */
102        pagesY = 1;
103        PaperDepth = image_dy + allow;
104    }
105    paper_centre_y = 20 + (pagesY * PaperDepth) / 2;
106    image_centre_y = Sc * (yMax + yMin) / 2;
107    yOrg = paper_centre_y - image_centre_y;
108
109    pages = pagesX * pagesY;
110}
111
112static void setting_missing(const char *v)
113{
114   fatalerror(/*Parameter `%s' missing in printer configuration file*/85, v);
115}
116
117static void setting_bad_value(const char *v, const char *p)
118{
119   fatalerror(/*Parameter `%s' has invalid value `%s' in printer configuration file*/82,
120              v, p);
121}
122
123char *
124as_string(const char *v, char *p)
125{
126   if (!p) setting_missing(v);
127   return p;
128}
129
130int
131as_int(const char *v, char *p, int min_val, int max_val)
132{
133   long val;
134   char *pEnd;
135   if (!p) setting_missing(v);
136   val = strtol(p, &pEnd, 10);
137   if (pEnd == p || val < (long)min_val || val > (long)max_val)
138      setting_bad_value(v, p);
139   osfree(p);
140   return (int)val;
141}
142
143/* Converts '0'-'9' to 0-9, 'A'-'F' to 10-15 and 'a'-'f' to 10-15.
144 * Undefined on other values */
145#define CHAR2HEX(C) (((C)+((C)>64?9:0))&15)
146
147unsigned long
148as_colour(const char *v, char *p)
149{
150   unsigned long val = 0xffffffff;
151   if (!p) setting_missing(v);
152   switch (tolower(*p)) {
153      case '#': {
154         char *q = p + 1;
155         while (isxdigit((unsigned char)*q)) q++;
156         if (q - p == 4) {
157            val = CHAR2HEX(p[1]) * 0x110000;
158            val |= CHAR2HEX(p[2]) * 0x1100;
159            val |= CHAR2HEX(p[3]) * 0x11;
160         } else if (q - p == 7) {
161            val = ((CHAR2HEX(p[1]) << 4) | CHAR2HEX(p[2])) << 16;
162            val |= ((CHAR2HEX(p[3]) << 4) | CHAR2HEX(p[4])) << 8;
163            val |= (CHAR2HEX(p[5]) << 4) | CHAR2HEX(p[6]);
164         }
165         break;
166      }
167      case 'a':
168         if (strcasecmp(p, "aqua") == 0) val = 0x00fffful;
169         break;
170      case 'b':
171         if (strcasecmp(p, "black") == 0) val = 0x000000ul;
172         else if (strcasecmp(p, "blue") == 0) val = 0x0000fful;
173         break;
174      case 'f':
175         if (strcasecmp(p, "fuchsia") == 0) val = 0xff00fful;
176         break;
177      case 'g':
178         if (strcasecmp(p, "gray") == 0) val = 0x808080ul;
179         else if (strcasecmp(p, "green") == 0) val = 0x008000ul;
180         break;
181      case 'l':
182         if (strcasecmp(p, "lime") == 0) val = 0x00ff00ul;
183         break;
184      case 'm':
185         if (strcasecmp(p, "maroon") == 0) val = 0x800000ul;
186         break;
187      case 'n':
188         if (strcasecmp(p, "navy") == 0) val = 0x000080ul;
189         break;
190      case 'o':
191         if (strcasecmp(p, "olive") == 0) val = 0x808000ul;
192         break;
193      case 'p':
194         if (strcasecmp(p, "purple") == 0) val = 0x800080ul;
195         break;
196      case 'r':
197         if (strcasecmp(p, "red") == 0) val = 0xff0000ul;
198         break;
199      case 's':
200         if (strcasecmp(p, "silver") == 0) val = 0xc0c0c0ul;
201         break;
202      case 't':
203         if (strcasecmp(p, "teal") == 0) val = 0x008080ul;
204         break;
205      case 'w':
206         if (strcasecmp(p, "white") == 0) val = 0xfffffful;
207         break;
208      case 'y':
209         if (strcasecmp(p, "yellow") == 0) val = 0xffff00ul;
210         break;
211   }
212   if (val == 0xffffffff) setting_bad_value(v, p);
213   osfree(p);
214   return val;
215}
216
217int
218as_bool(const char *v, char *p)
219{
220   return as_int(v, p, 0, 1);
221}
222
223double
224as_double(const char *v, char *p, double min_val, double max_val)
225{
226   double val;
227   char *pEnd;
228   if (!p) setting_missing(v);
229   val = strtod(p, &pEnd);
230   if (pEnd == p || val < min_val || val > max_val)
231      setting_bad_value(v, p);
232   osfree(p);
233   return val;
234}
235
236/*
237Codes:
238\\ -> '\'
239\xXX -> char with hex value XX
240\0, \n, \r, \t -> nul (0), newline (10), return (13), tab (9)
241\[ -> Esc (27)
242\? -> delete (127)
243\A - \Z -> (1) to (26)
244*/
245
246/* Takes a string, converts escape sequences in situ, and returns length
247 * of result (needed since converted string may contain '\0' */
248int
249as_escstring(const char *v, char *s)
250{
251   char *p, *q;
252   char c;
253   int pass;
254   static const char *escFr = "[nrt?0"; /* 0 is last so maps to the implicit \0 */
255   static const char *escTo = "\x1b\n\r\t\?";
256   bool fSyntax = fFalse;
257   if (!s) setting_missing(v);
258   for (pass = 0; pass <= 1; pass++) {
259      p = q = s;
260      while (*p) {
261         c = *p++;
262         if (c == '\\') {
263            c = *p++;
264            switch (c) {
265             case '\\': /* literal "\" */
266               break;
267             case 'x': /* hex digits */
268               if (isxdigit((unsigned char)*p) &&
269                   isxdigit((unsigned char)p[1])) {
270                  if (pass) c = (CHAR2HEX(*p) << 4) | CHAR2HEX(p[1]);
271                  p += 2;
272                  break;
273               }
274               /* \x not followed by 2 hex digits */
275               /* !!! FALLS THROUGH !!! */
276             case '\0': /* trailing \ is meaningless */
277               fSyntax = 1;
278               break;
279             default:
280               if (pass) {
281                  const char *t = strchr(escFr, c);
282                  if (t) {
283                     c = escTo[t - escFr];
284                     break;
285                  }
286                  /* \<capital letter> -> Ctrl-<letter> */
287                  if (isupper((unsigned char)c)) {
288                     c -= '@';
289                     break;
290                  }
291                  /* otherwise don't do anything to c (?) */
292                  break;
293               }
294            }
295         }
296         if (pass) *q++ = c;
297      }
298      if (fSyntax) {
299         SVX_ASSERT(pass == 0);
300         setting_bad_value(v, s);
301      }
302   }
303   return (q - s);
304}
305
306#define DEF_RATIO (1.0/(double)DEFAULT_SCALE)
307
308/* pick a scale which will make it fit in the desired size */
309void
310layout::pick_scale(int x, int y)
311{
312   double Sc_x, Sc_y;
313   /*    pagesY = ceil((image_dy+allow)/PaperDepth)
314    * so (image_dy+allow)/PaperDepth <= pagesY < (image_dy+allow)/PaperDepth+1
315    * so image_dy <= pagesY*PaperDepth-allow < image_dy+PaperDepth
316    * and Sc = image_dy / (yMax-yMin)
317    * so Sc <= (pagesY*PaperDepth-allow)/(yMax-yMin) < Sc+PaperDepth/(yMax-yMin)
318    */
319   Sc_x = Sc_y = DEF_RATIO;
320   if (PaperWidth > 0.0 && xMax > xMin)
321      Sc_x = (x * PaperWidth - 19.0) / (xMax - xMin);
322   if (PaperDepth > 0.0 && yMax > yMin) {
323      double allow = 21.0;
324      if (!Raw) allow += (view == EXTELEV ? 30.0 : 40.0);
325      Sc_y = (y * PaperDepth - allow) / (yMax - yMin);
326   }
327
328   Sc_x = min(Sc_x, Sc_y) * 0.99; /* shrink by 1% so we don't cock up */
329#if 0 /* this picks a nice (in some sense) ratio, but is too stingy */
330   double E = pow(10.0, floor(log10(Sc_x)));
331   Sc_x = floor(Sc_x / E) * E;
332#endif
333
334   double Scale_exact = 1000.0 / Sc_x;
335
336   /* trim to 2 s.f. (rounding up) */
337   double w = pow(10.0, floor(log10(Scale_exact) - 1.0));
338   Scale = ceil(Scale_exact / w) * w;
339}
340
341#if 0
342bool fBlankPage = fFalse;
343
344void print_all(MainFrm *m_parent, layout *l, device *pri) {
345    int cPasses, pass;
346    unsigned int cPagesPrinted;
347    const char *msg166;
348    int state;
349    char *p;
350    int old_charset;
351    int page, pageLim;
352    pageLim = l->pagesX*l->pagesY;
353    PaperWidth = l->PaperWidth;
354    PaperDepth = l->PaperDepth;
355    /* if no explicit Alloc, default to one pass */
356    cPasses = Pre(l->pages, l->title);
357
358    /* note down so we can switch to printer charset */
359    msg166 = msgPerm(/*Page %d of %d*/166);
360    select_charset(Charset());
361
362    /* used in printer's native charset in footer */
363    l->footer = msgPerm(/*Survey `%s'   Page %d (of %d)   Processed on %s*/167);
364
365    old_charset = select_charset(CHARSET_ISO_8859_1);
366    cPagesPrinted = 0;
367    page = state = 0;
368    p = l->szPages;
369    while (1) {
370        if (pageLim == 1) {
371            if (page == 0)
372                page = 1;
373            else
374                page = 0; /* we've already printed the only page */
375        } else if (!*l->szPages) {
376            page++;
377            if (page > pageLim) page = 0; /* all pages printed */
378        } else {
379            page = next_page(&state, &p, pageLim);
380        }
381        SVX_ASSERT(state >= 0); /* errors should have been caught above */
382        if (page == 0) break;
383        cPagesPrinted++;
384        if (l->pages > 1) {
385            putchar('\r');
386            printf(msg166, (int)cPagesPrinted, l->pages);
387        }
388        /* don't skip the page with the info box on */
389        if (l->SkipBlank && (int)page != (l->pagesY - 1) * l->pagesX + 1) {
390            pass = -1;
391            fBlankPage = fTrue;
392        } else {
393            pass = 0;
394            fBlankPage = fFalse;
395        }
396        print_page(m_parent, l, page, pass, cPasses);
397    }
398
399    Quit();
400    select_charset(old_charset);
401}
402#endif
Note: See TracBrowser for help on using the repository browser.