| 1 | /* avenprcore.cc | 
|---|
| 2 |  * Printer independent parts of Survex printer drivers | 
|---|
| 3 |  * Copyright (C) 1993-2002,2004,2005,2006,2010 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  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 <float.h> | 
|---|
| 34 |  | 
|---|
| 35 | #include "mainfrm.h" | 
|---|
| 36 |  | 
|---|
| 37 | #include "useful.h" | 
|---|
| 38 | #include "filename.h" | 
|---|
| 39 | #include "message.h" | 
|---|
| 40 | #include "filelist.h" | 
|---|
| 41 | #include "img.h" | 
|---|
| 42 | #include "avenprcore.h" | 
|---|
| 43 | #include "debug.h" | 
|---|
| 44 |  | 
|---|
| 45 | #if defined __WXMSW__ || defined __WXMAC__ | 
|---|
| 46 | # include <wx/dcprint.h> | 
|---|
| 47 | #else | 
|---|
| 48 | # include <wx/dcps.h> | 
|---|
| 49 | #endif | 
|---|
| 50 |  | 
|---|
| 51 | layout::layout(wxPageSetupDialogData* data) | 
|---|
| 52 |         : Labels(false), Crosses(false), Shots(true), Surface(false), | 
|---|
| 53 |           SkipBlank(false), Border(true), Cutlines(true), Raw(false), | 
|---|
| 54 |           title(), datestamp(), Scale(0), rot(0), tilt(0), | 
|---|
| 55 |           view(PLAN), scX(1), scY(1), xMin(0), xMax(-1), yMin(0), yMax(-1), | 
|---|
| 56 |           pagesX(1), pagesY(1), pages(1), xOrg(0), yOrg(0), footer() | 
|---|
| 57 | { | 
|---|
| 58 |     // Create a temporary wxPrinterDC/wxPostScriptDC so we can get access to | 
|---|
| 59 |     // the size of the printable area in mm to allow us to calculate how many | 
|---|
| 60 |     // pages will be needed. | 
|---|
| 61 | #if defined __WXMSW__ || defined __WXMAC__ | 
|---|
| 62 |     wxPrinterDC pdc(data->GetPrintData()); | 
|---|
| 63 | #else | 
|---|
| 64 |     wxPostScriptDC pdc(data->GetPrintData()); | 
|---|
| 65 | #endif | 
|---|
| 66 |     int width, depth; | 
|---|
| 67 |     pdc.GetSizeMM(&width, &depth); | 
|---|
| 68 |     width -= data->GetMarginBottomRight().x + data->GetMarginTopLeft().x; | 
|---|
| 69 |     PaperWidth = width; | 
|---|
| 70 |     depth -= data->GetMarginBottomRight().y + data->GetMarginTopLeft().y; | 
|---|
| 71 |     // Allow for the 10mm footer. | 
|---|
| 72 |     PaperDepth = depth - 10; | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | void | 
|---|
| 76 | layout::pages_required() { | 
|---|
| 77 |     double image_dx, image_dy; | 
|---|
| 78 |     double image_centre_x, image_centre_y; | 
|---|
| 79 |     double paper_centre_x, paper_centre_y; | 
|---|
| 80 |  | 
|---|
| 81 |     double allow = 21.0; | 
|---|
| 82 |     if (!Raw) allow += (view == EXTELEV ? 30.0 : 40.0); | 
|---|
| 83 |     double Sc = 1000 / Scale; | 
|---|
| 84 |     image_dx = (xMax - xMin) * Sc; | 
|---|
| 85 |     if (PaperWidth > 0.0) { | 
|---|
| 86 |         pagesX = (int)ceil((image_dx + 19.0) / PaperWidth); | 
|---|
| 87 |     } else { | 
|---|
| 88 |         /* paperwidth not fixed (eg window or roll printer/plotter) */ | 
|---|
| 89 |         pagesX = 1; | 
|---|
| 90 |         PaperWidth = image_dx + 19.0; | 
|---|
| 91 |     } | 
|---|
| 92 |     paper_centre_x = (pagesX * PaperWidth) / 2; | 
|---|
| 93 |     image_centre_x = Sc * (xMax + xMin) / 2; | 
|---|
| 94 |     xOrg = paper_centre_x - image_centre_x; | 
|---|
| 95 |  | 
|---|
| 96 |     image_dy = (yMax - yMin) * Sc; | 
|---|
| 97 |     if (PaperDepth > 0.0) { | 
|---|
| 98 |         pagesY = (int)ceil((image_dy + allow) / PaperDepth); | 
|---|
| 99 |     } else { | 
|---|
| 100 |         /* paperdepth not fixed (eg window or roll printer/plotter) */ | 
|---|
| 101 |         pagesY = 1; | 
|---|
| 102 |         PaperDepth = image_dy + allow; | 
|---|
| 103 |     } | 
|---|
| 104 |     paper_centre_y = 20 + (pagesY * PaperDepth) / 2; | 
|---|
| 105 |     image_centre_y = Sc * (yMax + yMin) / 2; | 
|---|
| 106 |     yOrg = paper_centre_y - image_centre_y; | 
|---|
| 107 |  | 
|---|
| 108 |     pages = pagesX * pagesY; | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | static void setting_missing(const char *v) | 
|---|
| 112 | { | 
|---|
| 113 |    fatalerror(/*Parameter `%s' missing in printer configuration file*/85, v); | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | static void setting_bad_value(const char *v, const char *p) | 
|---|
| 117 | { | 
|---|
| 118 |    fatalerror(/*Parameter `%s' has invalid value `%s' in printer configuration file*/82, | 
|---|
| 119 |               v, p); | 
|---|
| 120 | } | 
|---|
| 121 |  | 
|---|
| 122 | int | 
|---|
| 123 | as_int(const char *v, char *p, int min_val, int max_val) | 
|---|
| 124 | { | 
|---|
| 125 |    long val; | 
|---|
| 126 |    char *pEnd; | 
|---|
| 127 |    if (!p) setting_missing(v); | 
|---|
| 128 |    val = strtol(p, &pEnd, 10); | 
|---|
| 129 |    if (pEnd == p || val < (long)min_val || val > (long)max_val) | 
|---|
| 130 |       setting_bad_value(v, p); | 
|---|
| 131 |    osfree(p); | 
|---|
| 132 |    return (int)val; | 
|---|
| 133 | } | 
|---|
| 134 |  | 
|---|
| 135 | /* Converts '0'-'9' to 0-9, 'A'-'F' to 10-15 and 'a'-'f' to 10-15. | 
|---|
| 136 |  * Undefined on other values */ | 
|---|
| 137 | #define CHAR2HEX(C) (((C)+((C)>64?9:0))&15) | 
|---|
| 138 |  | 
|---|
| 139 | unsigned long | 
|---|
| 140 | as_colour(const char *v, char *p) | 
|---|
| 141 | { | 
|---|
| 142 |    unsigned long val = 0xffffffff; | 
|---|
| 143 |    if (!p) setting_missing(v); | 
|---|
| 144 |    switch (tolower(*p)) { | 
|---|
| 145 |       case '#': { | 
|---|
| 146 |          char *q = p + 1; | 
|---|
| 147 |          while (isxdigit((unsigned char)*q)) q++; | 
|---|
| 148 |          if (q - p == 4) { | 
|---|
| 149 |             val = CHAR2HEX(p[1]) * 0x110000; | 
|---|
| 150 |             val |= CHAR2HEX(p[2]) * 0x1100; | 
|---|
| 151 |             val |= CHAR2HEX(p[3]) * 0x11; | 
|---|
| 152 |          } else if (q - p == 7) { | 
|---|
| 153 |             val = ((CHAR2HEX(p[1]) << 4) | CHAR2HEX(p[2])) << 16; | 
|---|
| 154 |             val |= ((CHAR2HEX(p[3]) << 4) | CHAR2HEX(p[4])) << 8; | 
|---|
| 155 |             val |= (CHAR2HEX(p[5]) << 4) | CHAR2HEX(p[6]); | 
|---|
| 156 |          } | 
|---|
| 157 |          break; | 
|---|
| 158 |       } | 
|---|
| 159 |       case 'a': | 
|---|
| 160 |          if (strcasecmp(p, "aqua") == 0) val = 0x00fffful; | 
|---|
| 161 |          break; | 
|---|
| 162 |       case 'b': | 
|---|
| 163 |          if (strcasecmp(p, "black") == 0) val = 0x000000ul; | 
|---|
| 164 |          else if (strcasecmp(p, "blue") == 0) val = 0x0000fful; | 
|---|
| 165 |          break; | 
|---|
| 166 |       case 'f': | 
|---|
| 167 |          if (strcasecmp(p, "fuchsia") == 0) val = 0xff00fful; | 
|---|
| 168 |          break; | 
|---|
| 169 |       case 'g': | 
|---|
| 170 |          if (strcasecmp(p, "gray") == 0) val = 0x808080ul; | 
|---|
| 171 |          else if (strcasecmp(p, "green") == 0) val = 0x008000ul; | 
|---|
| 172 |          break; | 
|---|
| 173 |       case 'l': | 
|---|
| 174 |          if (strcasecmp(p, "lime") == 0) val = 0x00ff00ul; | 
|---|
| 175 |          break; | 
|---|
| 176 |       case 'm': | 
|---|
| 177 |          if (strcasecmp(p, "maroon") == 0) val = 0x800000ul; | 
|---|
| 178 |          break; | 
|---|
| 179 |       case 'n': | 
|---|
| 180 |          if (strcasecmp(p, "navy") == 0) val = 0x000080ul; | 
|---|
| 181 |          break; | 
|---|
| 182 |       case 'o': | 
|---|
| 183 |          if (strcasecmp(p, "olive") == 0) val = 0x808000ul; | 
|---|
| 184 |          break; | 
|---|
| 185 |       case 'p': | 
|---|
| 186 |          if (strcasecmp(p, "purple") == 0) val = 0x800080ul; | 
|---|
| 187 |          break; | 
|---|
| 188 |       case 'r': | 
|---|
| 189 |          if (strcasecmp(p, "red") == 0) val = 0xff0000ul; | 
|---|
| 190 |          break; | 
|---|
| 191 |       case 's': | 
|---|
| 192 |          if (strcasecmp(p, "silver") == 0) val = 0xc0c0c0ul; | 
|---|
| 193 |          break; | 
|---|
| 194 |       case 't': | 
|---|
| 195 |          if (strcasecmp(p, "teal") == 0) val = 0x008080ul; | 
|---|
| 196 |          break; | 
|---|
| 197 |       case 'w': | 
|---|
| 198 |          if (strcasecmp(p, "white") == 0) val = 0xfffffful; | 
|---|
| 199 |          break; | 
|---|
| 200 |       case 'y': | 
|---|
| 201 |          if (strcasecmp(p, "yellow") == 0) val = 0xffff00ul; | 
|---|
| 202 |          break; | 
|---|
| 203 |    } | 
|---|
| 204 |    if (val == 0xffffffff) setting_bad_value(v, p); | 
|---|
| 205 |    osfree(p); | 
|---|
| 206 |    return val; | 
|---|
| 207 | } | 
|---|
| 208 |  | 
|---|
| 209 | #define DEF_RATIO (1.0/(double)DEFAULT_SCALE) | 
|---|
| 210 |  | 
|---|
| 211 | /* pick a scale which will make it fit in the desired size */ | 
|---|
| 212 | void | 
|---|
| 213 | layout::pick_scale(int x, int y) | 
|---|
| 214 | { | 
|---|
| 215 |    double Sc_x, Sc_y; | 
|---|
| 216 |    /*    pagesY = ceil((image_dy+allow)/PaperDepth) | 
|---|
| 217 |     * so (image_dy+allow)/PaperDepth <= pagesY < (image_dy+allow)/PaperDepth+1 | 
|---|
| 218 |     * so image_dy <= pagesY*PaperDepth-allow < image_dy+PaperDepth | 
|---|
| 219 |     * and Sc = image_dy / (yMax-yMin) | 
|---|
| 220 |     * so Sc <= (pagesY*PaperDepth-allow)/(yMax-yMin) < Sc+PaperDepth/(yMax-yMin) | 
|---|
| 221 |     */ | 
|---|
| 222 |    Sc_x = Sc_y = DEF_RATIO; | 
|---|
| 223 |    if (PaperWidth > 0.0 && xMax > xMin) | 
|---|
| 224 |       Sc_x = (x * PaperWidth - 19.0) / (xMax - xMin); | 
|---|
| 225 |    if (PaperDepth > 0.0 && yMax > yMin) { | 
|---|
| 226 |       double allow = 21.0; | 
|---|
| 227 |       if (!Raw) allow += (view == EXTELEV ? 30.0 : 40.0); | 
|---|
| 228 |       Sc_y = (y * PaperDepth - allow) / (yMax - yMin); | 
|---|
| 229 |    } | 
|---|
| 230 |  | 
|---|
| 231 |    Sc_x = min(Sc_x, Sc_y) * 0.99; /* shrink by 1% so we don't cock up */ | 
|---|
| 232 | #if 0 /* this picks a nice (in some sense) ratio, but is too stingy */ | 
|---|
| 233 |    double E = pow(10.0, floor(log10(Sc_x))); | 
|---|
| 234 |    Sc_x = floor(Sc_x / E) * E; | 
|---|
| 235 | #endif | 
|---|
| 236 |  | 
|---|
| 237 |    double Scale_exact = 1000.0 / Sc_x; | 
|---|
| 238 |  | 
|---|
| 239 |    /* trim to 2 s.f. (rounding up) */ | 
|---|
| 240 |    double w = pow(10.0, floor(log10(Scale_exact) - 1.0)); | 
|---|
| 241 |    Scale = ceil(Scale_exact / w) * w; | 
|---|
| 242 | } | 
|---|
| 243 |  | 
|---|
| 244 | #if 0 | 
|---|
| 245 | bool fBlankPage = fFalse; | 
|---|
| 246 |  | 
|---|
| 247 | void print_all(MainFrm *m_parent, layout *l, device *pri) { | 
|---|
| 248 |     int cPasses, pass; | 
|---|
| 249 |     unsigned int cPagesPrinted; | 
|---|
| 250 |     const char *msg166; | 
|---|
| 251 |     int state; | 
|---|
| 252 |     char *p; | 
|---|
| 253 |     int old_charset; | 
|---|
| 254 |     int page, pageLim; | 
|---|
| 255 |     pageLim = l->pagesX*l->pagesY; | 
|---|
| 256 |     PaperWidth = l->PaperWidth; | 
|---|
| 257 |     PaperDepth = l->PaperDepth; | 
|---|
| 258 |     /* if no explicit Alloc, default to one pass */ | 
|---|
| 259 |     cPasses = Pre(l->pages, l->title); | 
|---|
| 260 |  | 
|---|
| 261 |     /* note down so we can switch to printer charset */ | 
|---|
| 262 |     msg166 = msgPerm(/*Page %d of %d*/166); | 
|---|
| 263 |     select_charset(Charset()); | 
|---|
| 264 |  | 
|---|
| 265 |     /* used in printer's native charset in footer */ | 
|---|
| 266 |     l->footer = msgPerm(/*Survey `%s'   Page %d (of %d)   Processed on %s*/167); | 
|---|
| 267 |  | 
|---|
| 268 |     old_charset = select_charset(CHARSET_ISO_8859_1); | 
|---|
| 269 |     cPagesPrinted = 0; | 
|---|
| 270 |     page = state = 0; | 
|---|
| 271 |     p = l->szPages; | 
|---|
| 272 |     while (1) { | 
|---|
| 273 |         if (pageLim == 1) { | 
|---|
| 274 |             if (page == 0) | 
|---|
| 275 |                 page = 1; | 
|---|
| 276 |             else | 
|---|
| 277 |                 page = 0; /* we've already printed the only page */ | 
|---|
| 278 |         } else if (!*l->szPages) { | 
|---|
| 279 |             page++; | 
|---|
| 280 |             if (page > pageLim) page = 0; /* all pages printed */ | 
|---|
| 281 |         } else { | 
|---|
| 282 |             page = next_page(&state, &p, pageLim); | 
|---|
| 283 |         } | 
|---|
| 284 |         SVX_ASSERT(state >= 0); /* errors should have been caught above */ | 
|---|
| 285 |         if (page == 0) break; | 
|---|
| 286 |         cPagesPrinted++; | 
|---|
| 287 |         if (l->pages > 1) { | 
|---|
| 288 |             putchar('\r'); | 
|---|
| 289 |             printf(msg166, (int)cPagesPrinted, l->pages); | 
|---|
| 290 |         } | 
|---|
| 291 |         /* don't skip the page with the info box on */ | 
|---|
| 292 |         if (l->SkipBlank && (int)page != (l->pagesY - 1) * l->pagesX + 1) { | 
|---|
| 293 |             pass = -1; | 
|---|
| 294 |             fBlankPage = fTrue; | 
|---|
| 295 |         } else { | 
|---|
| 296 |             pass = 0; | 
|---|
| 297 |             fBlankPage = fFalse; | 
|---|
| 298 |         } | 
|---|
| 299 |         print_page(m_parent, l, page, pass, cPasses); | 
|---|
| 300 |     } | 
|---|
| 301 |  | 
|---|
| 302 |     Quit(); | 
|---|
| 303 |     select_charset(old_charset); | 
|---|
| 304 | } | 
|---|
| 305 | #endif | 
|---|