source: branches/help/AWT/AWT_canio.cxx

Last change on this file was 18730, checked in by westram, 3 years ago
  • remove trailing whitespace from c source.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.9 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : AWT_canio.cxx                                      //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Institute of Microbiology (Technical University Munich)        //
7//   http://www.arb-home.de/                                        //
8//                                                                  //
9// ================================================================ //
10
11#include "awt_canvas.hxx"
12
13#include <aw_file.hxx>
14#include <aw_awar.hxx>
15#include <aw_msg.hxx>
16#include <arb_progress.h>
17#include <aw_root.hxx>
18#include <arbdbt.h>
19#include <arb_defs.h>
20#include <arb_strbuf.h>
21#include <arb_file.h>
22
23using namespace AW;
24
25#define awt_assert(cond) arb_assert(cond)
26
27// --------------------------------------------------------------------------------
28
29#define AWAR_CANIO                 "NT/print/"
30#define AWAR_CANIO_LANDSCAPE       AWAR_CANIO "landscape"
31#define AWAR_CANIO_CLIP            AWAR_CANIO "clip"
32#define AWAR_CANIO_HANDLES         AWAR_CANIO "handles"
33#define AWAR_CANIO_COLOR           AWAR_CANIO "color"
34#define AWAR_CANIO_DEST            AWAR_CANIO "dest"
35#define AWAR_CANIO_PRINTER         AWAR_CANIO "printer"
36#define AWAR_CANIO_OVERLAP_WANTED  AWAR_CANIO "overlap"
37#define AWAR_CANIO_OVERLAP_PERCENT AWAR_CANIO "operc"
38#define AWAR_CANIO_BORDERSIZE      AWAR_CANIO "border"
39#define AWAR_CANIO_PAPER           AWAR_CANIO "paper"
40#define AWAR_CANIO_PAPER_USABLE    AWAR_CANIO "useable"
41#define AWAR_CANIO_F2DBUG          AWAR_CANIO "f2dbug"
42#define AWAR_CANIO_PAGES           AWAR_CANIO "pages"
43#define AWAR_CANIO_PAGELOCK        AWAR_CANIO "plock"
44
45#define AWAR_CANIO_TMP "tmp/" AWAR_CANIO
46
47#define AWAR_CANIO_MAGNIFICATION AWAR_CANIO_TMP "magnification"
48#define AWAR_CANIO_OVERLAP       AWAR_CANIO_TMP "overlap"
49#define AWAR_CANIO_GFX_SX        AWAR_CANIO_TMP "gsizex" // graphic size in inch
50#define AWAR_CANIO_GFX_SY        AWAR_CANIO_TMP "gsizey"
51#define AWAR_CANIO_OUT_SX        AWAR_CANIO_TMP "osizex" // output size in inch
52#define AWAR_CANIO_OUT_SY        AWAR_CANIO_TMP "osizey"
53#define AWAR_CANIO_PAPER_SX      AWAR_CANIO_TMP "psizex" // paper size in inch
54#define AWAR_CANIO_PAPER_SY      AWAR_CANIO_TMP "psizey"
55#define AWAR_CANIO_PAGE_SX       AWAR_CANIO_TMP "sizex"  // size in pages
56#define AWAR_CANIO_PAGE_SY       AWAR_CANIO_TMP "sizey"
57
58#define AWAR_CANIO_FILE_BASE   AWAR_CANIO_TMP "file"
59#define AWAR_CANIO_FILE_NAME   AWAR_CANIO_FILE_BASE "/file_name"
60#define AWAR_CANIO_FILE_DIR    AWAR_CANIO_FILE_BASE "/directory"
61#define AWAR_CANIO_FILE_FILTER AWAR_CANIO_FILE_BASE "/filter"
62
63// --------------------------------------------------------------------------------
64
65enum PrintDest {
66    PDEST_PRINTER    = 0,
67    PDEST_POSTSCRIPT = 1,
68    PDEST_PREVIEW    = 2,
69};
70
71// --------------------------------------------------------------------------------
72
73enum LengthUnit { INCH, MM };
74
75static const float mm_per_inch = 25.4;
76inline float inch2mm(float inches) { return inches*mm_per_inch; }
77inline float mm2inch(float mms) { return mms/mm_per_inch; }
78
79class PaperFormat {
80    const char *description;
81    const char *fig2dev_val;
82    LengthUnit  unit;
83    float      shortSide, longSide;
84
85public:
86    PaperFormat(const char *name, LengthUnit lu, float shortSide_, float longSide_)
87        : description(name),
88          fig2dev_val(name),
89          unit(lu),
90          shortSide(shortSide_),
91          longSide(longSide_)
92    {
93        awt_assert(shortSide<longSide);
94    }
95    PaperFormat(const char *aname, const char *fname, LengthUnit lu, float shortSide_, float longSide_)
96        : description(aname),
97          fig2dev_val(fname),
98          unit(lu),
99          shortSide(shortSide_),
100          longSide(longSide_)
101    {
102        awt_assert(shortSide<longSide);
103    }
104
105    float short_inch() const { return unit == INCH ? shortSide : mm2inch(shortSide); }
106    float long_inch()  const { return unit == INCH ? longSide : mm2inch(longSide); }
107
108    const char *get_description() const { return description; }
109    const char *get_fig2dev_val() const { return fig2dev_val; }
110};
111
112// (c&p from fig2dev:)
113//  Available paper sizes are:
114//      "Letter" (8.5" x 11" also "A"),
115//      "Legal" (11" x 14")
116//      "Ledger" (11" x 17"),
117//      "Tabloid" (17" x 11", really Ledger in Landscape mode),
118//      "A" (8.5" x 11" also "Letter"),
119//      "B" (11" x 17" also "Ledger"),
120//      "C" (17" x 22"),
121//      "D" (22" x 34"),
122//      "E" (34" x 44"),
123//      "A4" (21  cm x  29.7cm),
124//      "A3" (29.7cm x  42  cm),
125//      "A2" (42  cm x  59.4cm),
126//      "A1" (59.4cm x  84.1cm),
127//      "A0" (84.1cm x 118.9cm),
128//      and "B5" (18.2cm x 25.7cm).
129
130static PaperFormat knownPaperFormat[] = {
131    PaperFormat("A4", MM, 210, 297), // first is the default
132    PaperFormat("A3", MM, 297, 420),
133    PaperFormat("A2", MM, 420, 594),
134    PaperFormat("A1", MM, 594, 841),
135    PaperFormat("A0", MM, 841, 1189),
136    PaperFormat("B5", MM, 182, 257),
137
138    PaperFormat("A (Letter)", "A", INCH, 8.5, 11),
139    PaperFormat("Legal",           INCH, 11, 14),
140    PaperFormat("B (Ledger)", "B", INCH, 11, 17),
141    PaperFormat("C",          "C", INCH, 17, 22),
142    PaperFormat("D",          "D", INCH, 22, 34),
143    PaperFormat("E",          "E", INCH, 34, 44),
144};
145
146// --------------------------------------------------------------------------------
147
148static Rectangle get_drawsize(AWT_canvas *scr, bool draw_all) {
149    // returns size of drawn graphic in screen-coordinates
150
151    Rectangle       drawsize;
152    GB_transaction  ta(scr->gb_main);
153    AW_device_size *size_device = scr->aww->get_size_device(AW_MIDDLE_AREA);
154
155    if (draw_all) {
156        size_device->reset();
157        size_device->zoom(scr->trans_to_fit);
158        size_device->set_filter(AW_PRINTER|AW_PRINTER_EXT);
159        scr->gfx->show(size_device);
160        drawsize = size_device->get_size_information();
161    }
162    else {
163        drawsize = Rectangle(size_device->get_area_size(), INCLUSIVE_OUTLINE);
164    }
165
166    return drawsize;
167}
168
169static Rectangle add_border_to_drawsize(const Rectangle& drawsize, float border_percent) {
170    float  borderratio     = border_percent*.01;
171    float  draw2bordersize = -borderratio/(borderratio-1.0);
172    Vector bordersize      = drawsize.diagonal() * (draw2bordersize*0.5);
173
174    return Rectangle(drawsize.upper_left_corner()-bordersize,
175                     drawsize.lower_right_corner()+bordersize);
176}
177
178static void awt_print_tree_check_size(UNFIXED, AWT_canvas *scr) {
179    AW_root   *awr         = scr->awr;
180    long       draw_all    = awr->awar(AWAR_CANIO_CLIP)->read_int();
181    float      border      = awr->awar(AWAR_CANIO_BORDERSIZE)->read_float();
182    Rectangle  drawsize    = get_drawsize(scr, draw_all);
183    Rectangle  with_border = add_border_to_drawsize(drawsize, border);
184
185    awr->awar(AWAR_CANIO_GFX_SX)->write_float(with_border.width()/DPI_SCREEN);
186    awr->awar(AWAR_CANIO_GFX_SY)->write_float(with_border.height()/DPI_SCREEN);
187}
188
189inline int xy2pages(float sx, float sy) {
190    return int(sx+0.99)*int(sy+0.99);
191}
192
193static bool allow_page_size_check_cb = true;
194static bool allow_overlap_toggled_cb = true;
195
196inline void set_paper_size_xy(AW_root *awr, float px, float py) {
197    // modify papersize but perform only one callback
198
199    bool old_allow           = allow_page_size_check_cb;
200    allow_page_size_check_cb = false;
201    awr->awar(AWAR_CANIO_PAPER_SX)->write_float(px);
202    allow_page_size_check_cb = old_allow;
203    awr->awar(AWAR_CANIO_PAPER_SY)->write_float(py);
204}
205
206static void overlap_toggled_cb(AW_root *awr) {
207    if (allow_overlap_toggled_cb) {
208        int new_val = awr->awar(AWAR_CANIO_OVERLAP)->read_int();
209        awr->awar(AWAR_CANIO_OVERLAP_WANTED)->write_int(new_val);
210    }
211}
212
213static long calc_mag_from_psize(AW_root *awr, float papersize, float gfxsize, float wantedpages, bool use_x) {
214    bool  wantOverlap = awr->awar(AWAR_CANIO_OVERLAP_WANTED)->read_int();
215    float usableSize  = 0;
216
217    if (wantOverlap && wantedpages>1) {
218        float overlapPercent = awr->awar(AWAR_CANIO_OVERLAP_PERCENT)->read_float();
219        float usableRatio    = (100.0-overlapPercent)/100.0;
220
221        // See also fig2devbug in page_size_check_cb()
222        bool fig2devbug = !use_x && awr->awar(AWAR_CANIO_F2DBUG)->read_int();
223        if (fig2devbug) {
224            bool landscape = awr->awar(AWAR_CANIO_LANDSCAPE)->read_int();
225            fig2devbug     = fig2devbug && !landscape; // only occurs in portrait mode
226        }
227
228        if (fig2devbug) {
229            usableSize = wantedpages*papersize*usableRatio;
230        }
231        else {
232            usableSize = (papersize*usableRatio)*(wantedpages-1)+papersize;
233        }
234    }
235    else {
236        usableSize = wantedpages*papersize;
237    }
238
239    return usableSize*100/gfxsize; // always "round" to floor
240}
241
242static void set_mag_from_psize(AW_root *awr, bool use_x) {
243    const char *papersize_name   = use_x ? AWAR_CANIO_PAPER_SX : AWAR_CANIO_PAPER_SY;
244    const char *gfxsize_name     = use_x ? AWAR_CANIO_GFX_SX : AWAR_CANIO_GFX_SY;
245    const char *wantedpages_name = use_x ? AWAR_CANIO_PAGE_SX : AWAR_CANIO_PAGE_SY;
246
247    float papersize   = awr->awar(papersize_name)->read_float();
248    float gfxsize     = awr->awar(gfxsize_name)->read_float();
249    float wantedpages = awr->awar(wantedpages_name)->read_float();
250    long  mag         = calc_mag_from_psize(awr, papersize, gfxsize, wantedpages, use_x);
251
252    awr->awar(AWAR_CANIO_MAGNIFICATION)->write_int(mag);
253}
254
255static void fit_pages(AW_root *awr, int wanted_pages, bool allow_orientation_change) {
256    int         best_orientation    = -1;
257    const char *best_zoom_awar_name = NULp;
258    float       best_zoom           = 0;
259    int         best_magnification  = 0;
260    int         best_pages          = 0;
261
262    bool lockpages = awr->awar(AWAR_CANIO_PAGELOCK)->read_int();
263    awr->awar(AWAR_CANIO_PAGELOCK)->write_int(0);
264
265    if (!allow_orientation_change) {
266        best_orientation = awr->awar(AWAR_CANIO_LANDSCAPE)->read_int();
267    }
268
269    for (int o = 0; o <= 1; ++o) {
270        if (!allow_orientation_change && o != best_orientation) continue;
271
272        awr->awar(AWAR_CANIO_LANDSCAPE)->write_int(o); // set orientation (calls page_size_check_cb)
273
274        for (int xy = 0; xy <= 1; ++xy) {
275            const char *awar_name = xy == 0 ? AWAR_CANIO_PAGE_SX : AWAR_CANIO_PAGE_SY;
276
277            for (int pcount = 1; pcount <= wanted_pages; pcount++) {
278                float zoom = pcount*1.0;
279                awr->awar(awar_name)->write_float(zoom); // set zoom (x or y)
280
281                set_mag_from_psize(awr, xy == 0);
282
283                float sx    = awr->awar(AWAR_CANIO_PAGE_SX)->read_float();
284                float sy    = awr->awar(AWAR_CANIO_PAGE_SY)->read_float();
285                int   pages = xy2pages(sx, sy);
286
287                if (pages>wanted_pages) break; // pcount-loop
288
289                if (pages <= wanted_pages && pages >= best_pages) {
290                    int magnification = awr->awar(AWAR_CANIO_MAGNIFICATION)->read_int();    // read calculated magnification
291                    if (magnification>best_magnification) {
292                        // fits on wanted_pages and is best result yet
293                        best_magnification  = magnification;
294                        best_orientation    = o;
295                        best_zoom_awar_name = awar_name;
296                        best_zoom           = zoom;
297                        best_pages          = pages;
298                    }
299                }
300            }
301        }
302    }
303
304    if (best_zoom_awar_name) {
305        // take the best found values :
306        awr->awar(AWAR_CANIO_LANDSCAPE)->write_int(best_orientation);
307        awr->awar(best_zoom_awar_name)->write_float(best_zoom);
308        awr->awar(AWAR_CANIO_PAGES)->write_int(best_pages);
309        awr->awar(AWAR_CANIO_MAGNIFICATION)->write_int(best_magnification);
310
311        if (best_pages != wanted_pages) {
312            aw_message(GBS_global_string("That didn't fit on %i page(s) - using %i page(s)",
313                                         wanted_pages, best_pages));
314        }
315    }
316    else {
317        aw_message(GBS_global_string("That didn't fit on %i page(s) - impossible settings", wanted_pages));
318    }
319
320    awr->awar(AWAR_CANIO_PAGELOCK)->write_int(lockpages);
321}
322
323static void page_size_check_cb(AW_root *awr) {
324    if (!allow_page_size_check_cb) return;
325
326    bool landscape    = awr->awar(AWAR_CANIO_LANDSCAPE)->read_int();
327    bool lockpages    = awr->awar(AWAR_CANIO_PAGELOCK)->read_int();
328    int  locked_pages = awr->awar(AWAR_CANIO_PAGES)->read_int();
329
330    float px = awr->awar(AWAR_CANIO_PAPER_SX)->read_float(); // paper-size
331    float py = awr->awar(AWAR_CANIO_PAPER_SY)->read_float();
332
333    if (landscape != (px>py)) {
334        set_paper_size_xy(awr, py, px); // recalls this function
335        return;
336    }
337
338    long magnification = awr->awar(AWAR_CANIO_MAGNIFICATION)->read_int();
339
340    float gx = awr->awar(AWAR_CANIO_GFX_SX)->read_float(); // graphic size
341    float gy = awr->awar(AWAR_CANIO_GFX_SY)->read_float();
342
343    // output size
344    float ox = (gx*magnification)/100; // resulting size of output in inches
345    float oy = (gy*magnification)/100;
346    awr->awar(AWAR_CANIO_OUT_SX)->write_float(ox);
347    awr->awar(AWAR_CANIO_OUT_SY)->write_float(oy);
348
349    bool wantOverlap = awr->awar(AWAR_CANIO_OVERLAP_WANTED)->read_int();
350    bool useOverlap  = awr->awar(AWAR_CANIO_OVERLAP)->read_int();
351
352    float sx = 0.0; // resulting pages
353    float sy = 0.0;
354
355    bool fits_on_one_page = (ox <= px && oy <= py);
356
357    if (wantOverlap && !fits_on_one_page) {
358        float overlapPercent = awr->awar(AWAR_CANIO_OVERLAP_PERCENT)->read_float();
359        float pageRatio      = (100.0-overlapPercent)/100.0;
360
361        float rpx = px*pageRatio; // usable page-size (due to overlap)
362        float rpy = py*pageRatio;
363
364        while (ox>px) { ox -= rpx; sx += 1.0; }
365        sx += ox/px;
366
367        bool fig2devbug = !landscape;
368        if (fig2devbug) fig2devbug = awr->awar(AWAR_CANIO_F2DBUG)->read_int();
369
370        if (fig2devbug) {
371            // fig2dev has a bug with printing multiple portrait pages with overlap:
372            // Regardless of whether there is a needed overlapping in y-direction
373            // it prints a empty border at top of all top-row-pages and then clips
374            // the fig in the bottom-row (even if there is only one row).
375            // See also fig2devbug in calc_mag_from_psize()
376            sy += oy/rpy;
377        }
378        else {
379            while (oy>py) { oy -= rpy; sy += 1.0; }
380            sy += oy/py;
381        }
382    }
383    else {
384        sx = ox/px;
385        sy = oy/py;
386    }
387
388    // write amount of pages needed
389    awr->awar(AWAR_CANIO_PAGE_SX)->write_float(sx);
390    awr->awar(AWAR_CANIO_PAGE_SY)->write_float(sy);
391
392    int pages = xy2pages(sx, sy);
393    if (lockpages) {
394        fit_pages(awr, locked_pages, false); // Note: recurses with !lockpages
395        return;
396    }
397
398    awr->awar(AWAR_CANIO_PAGES)->write_int(pages);
399
400    // correct DISPLAYED overlapping..
401    bool willUseOverlap = wantOverlap && (pages != 1);
402    if (willUseOverlap != useOverlap) {
403        bool old_allow           = allow_overlap_toggled_cb;
404        allow_overlap_toggled_cb = false; // ..but do not modify wanted overlapping
405
406        awr->awar(AWAR_CANIO_OVERLAP)->write_int(willUseOverlap);
407
408        allow_overlap_toggled_cb = old_allow;
409    }
410}
411
412inline double round_psize(double psize) { return AW_INT(psize*10)/10.0; }
413
414static void paper_changed_cb(AW_root *awr) {
415    int                paper     = awr->awar(AWAR_CANIO_PAPER)->read_int();
416    const PaperFormat& format    = knownPaperFormat[paper];
417    bool               landscape = awr->awar(AWAR_CANIO_LANDSCAPE)->read_int();
418    float              useable   = awr->awar(AWAR_CANIO_PAPER_USABLE)->read_float()/100.0;
419
420    if (landscape) {
421        set_paper_size_xy(awr, useable*format.long_inch(), useable*format.short_inch());
422    }
423    else {
424        set_paper_size_xy(awr, useable*format.short_inch(), useable*format.long_inch());
425    }
426}
427
428// --------------------------------------------------------------------------------
429
430static bool export_awars_created = false;
431static bool print_awars_created = false;
432
433static void create_fig_export_awars(AW_root *awr) {
434    if (!export_awars_created) {
435        AW_default def = AW_ROOT_DEFAULT;
436
437        awr->awar_int(AWAR_CANIO_CLIP, 0, def);
438        awr->awar_int(AWAR_CANIO_HANDLES, 1, def);
439        awr->awar_int(AWAR_CANIO_COLOR, 1, def);
440
441        awr->awar_string(AWAR_CANIO_FILE_NAME, "print.fig", def);
442        awr->awar_string(AWAR_CANIO_FILE_DIR, "", def);
443        awr->awar_string(AWAR_CANIO_FILE_FILTER, "fig", def);
444
445        awr->awar_int(AWAR_CANIO_LANDSCAPE, 0, def);
446        awr->awar_int(AWAR_CANIO_MAGNIFICATION, 100, def);
447
448        // constraints:
449
450        awr->awar(AWAR_CANIO_MAGNIFICATION)->set_minmax(1, 10000);
451
452        export_awars_created = true;
453    }
454}
455
456static void resetFiletype(AW_root *awr, const char *filter, const char *defaultFilename) {
457    AW_awar *awar_filter    = awr->awar(AWAR_CANIO_FILE_FILTER);
458    char    *current_filter = awar_filter->read_string();
459
460    if (strcmp(current_filter, filter) != 0) {
461        awar_filter->write_string(filter);
462        awr->awar(AWAR_CANIO_FILE_NAME)->write_string(defaultFilename);
463    }
464    free(current_filter);
465}
466
467static void create_print_awars(AW_root *awr, AWT_canvas *scr) {
468    create_fig_export_awars(awr);
469
470    if (!print_awars_created) {
471        AW_default def = AW_ROOT_DEFAULT;
472
473        awr->awar_int(AWAR_CANIO_PAGES, 1, def);
474        awr->awar_int(AWAR_CANIO_PAGELOCK, 1, def);
475
476        awr->awar_int(AWAR_CANIO_OVERLAP_WANTED, 1, def);
477        awr->awar_int(AWAR_CANIO_OVERLAP, 1, def)->add_callback(overlap_toggled_cb);
478        awr->awar_float(AWAR_CANIO_OVERLAP_PERCENT, 13.0, def); // determined
479
480        awr->awar_int(AWAR_CANIO_F2DBUG, 1, def); // bug still exists in most recent version (3.2 5d from July 23, 2010)
481
482        awr->awar_float(AWAR_CANIO_BORDERSIZE, 0.0, def);
483
484        awr->awar_float(AWAR_CANIO_GFX_SX);
485        awr->awar_float(AWAR_CANIO_GFX_SY);
486
487        awr->awar_float(AWAR_CANIO_OUT_SX);
488        awr->awar_float(AWAR_CANIO_OUT_SY);
489
490        awr->awar_float(AWAR_CANIO_PAPER_SX);
491        awr->awar_float(AWAR_CANIO_PAPER_SY);
492
493        awr->awar_int(AWAR_CANIO_PAPER, 0)->add_callback(paper_changed_cb); // sets first format (A4)
494        awr->awar_float(AWAR_CANIO_PAPER_USABLE, 95)->add_callback(paper_changed_cb); // 95% of paper are usable
495
496        awr->awar_float(AWAR_CANIO_PAGE_SX);
497        awr->awar_float(AWAR_CANIO_PAGE_SY);
498
499        awr->awar_int(AWAR_CANIO_DEST);
500
501        {
502            char *print_command = getenv("PRINTER")
503                ? GBS_eval_env("lpr -h -P$(PRINTER)")
504                : ARB_strdup("lpr -h");
505            awr->awar_string(AWAR_CANIO_PRINTER, print_command, def);
506            free(print_command);
507        }
508
509        // constraints and automatics:
510
511        awr->awar(AWAR_CANIO_PAPER_SX)->set_minmax(0.1, 100);
512        awr->awar(AWAR_CANIO_PAPER_SY)->set_minmax(0.1, 100);
513
514
515        RootCallback checkSizeCb = makeRootCallback(awt_print_tree_check_size, scr);
516        checkSizeCb(NULp);
517        awr->awar(AWAR_CANIO_CLIP)      ->add_callback(checkSizeCb);
518        awr->awar(AWAR_CANIO_BORDERSIZE)->add_callback(checkSizeCb);
519
520        { // add callbacks for page recalculation
521            const char *checked_awars[] = {
522                AWAR_CANIO_MAGNIFICATION,
523                AWAR_CANIO_LANDSCAPE,
524                AWAR_CANIO_BORDERSIZE,
525                AWAR_CANIO_OVERLAP_WANTED, AWAR_CANIO_OVERLAP_PERCENT,
526                AWAR_CANIO_F2DBUG,
527                AWAR_CANIO_PAPER_SX,       AWAR_CANIO_PAPER_SY,
528                AWAR_CANIO_GFX_SX,         AWAR_CANIO_GFX_SY,
529                NULp
530            };
531            for (int ca = 0; checked_awars[ca]; ca++) {
532                awr->awar(checked_awars[ca])->add_callback(page_size_check_cb);
533            }
534        }
535
536        paper_changed_cb(awr); // also calls page_size_check_cb
537        print_awars_created = true;
538    }
539}
540
541// --------------------------------------------------------------------------------
542
543static GB_ERROR canvas_to_xfig(AWT_canvas *scr, const char *xfig_name, bool add_invisibles, float border) {
544    // if 'add_invisibles' is true => print 2 invisible dots to make fig2dev center correctly
545
546    GB_transaction  ta(scr->gb_main);
547    AW_root        *awr = scr->awr;
548
549    bool draw_all  = awr->awar(AWAR_CANIO_CLIP)->read_int();
550    bool handles   = awr->awar(AWAR_CANIO_HANDLES)->read_int();
551    bool use_color = awr->awar(AWAR_CANIO_COLOR)->read_int();
552
553    AW_device_print *device = scr->aww->get_print_device(AW_MIDDLE_AREA);
554
555    device->reset();
556    device->set_color_mode(use_color);
557
558    GB_ERROR error = device->open(xfig_name);
559    if (!error) {
560        Rectangle drawsize = get_drawsize(scr, draw_all);
561        Rectangle world_drawsize;
562
563        if (draw_all) {
564            Rectangle with_border = add_border_to_drawsize(drawsize, border);
565
566            double zoom = scr->trans_to_fit;
567            device->zoom(zoom); // same zoom as used by get_drawsize above
568
569            world_drawsize = device->rtransform(drawsize);
570
571            Vector ulc2origin = Origin-with_border.upper_left_corner();
572            Vector offset     = device->rtransform(ulc2origin)*device->get_unscale();
573
574            device->set_offset(offset);
575
576            device->set_bottom_clip_border((int)(with_border.height()+1), true);
577            device->set_right_clip_border((int)(with_border.width()+1), true);
578        }
579        else {
580            scr->init_device(device);
581            world_drawsize = device->rtransform(drawsize);
582        }
583
584        AW_bitset filter       = AW_PRINTER;
585        if (handles) filter   |= AW_PRINTER_EXT;
586        if (!draw_all) filter |= AW_PRINTER_CLIP;
587
588        device->set_filter(filter);
589        scr->gfx->show(device);
590
591        if (add_invisibles) {
592            Position ul = world_drawsize.upper_left_corner();
593            Position lr = world_drawsize.lower_right_corner();
594
595            // move invisible points towards center (in case they are clipped away)
596            Vector stepInside = device->rtransform(Vector(1, 1));
597            int maxloop = 10;
598
599            bool drawnUL = false;
600            bool drawnLR = false;
601
602            while (!(drawnLR && drawnUL) && maxloop-->0) {
603                if (!drawnUL) {
604                    drawnUL  = device->invisible(ul);
605                    ul      += stepInside;
606                }
607                if (!drawnLR) {
608                    drawnLR  = device->invisible(lr);
609                    lr      -= stepInside;
610                }
611            }
612            awt_assert(drawnLR && drawnUL);
613        }
614
615        device->close();
616    }
617    return error;
618}
619
620// --------------------------------------------------------------------------------
621
622static void canvas_to_xfig_and_run_xfig(AW_window *aww, AWT_canvas *scr) {
623    AW_root *awr  = aww->get_root();
624    char    *xfig = AW_get_selected_fullname(awr, AWAR_CANIO_FILE_BASE);
625
626    GB_ERROR error = NULp;
627    if (xfig[0] == 0) {
628        error = "Please enter a file name";
629    }
630    else {
631        error = canvas_to_xfig(scr, xfig, true, 0.0);
632        if (!error) {
633            awr->awar(AWAR_CANIO_FILE_DIR)->touch(); // reload dir to show created xfig
634            char *quotedXfig = GBK_singlequote(xfig);
635
636            error = GBK_system(GBS_global_string("xfig %s &", quotedXfig));
637            free(quotedXfig);
638        }
639    }
640    if (error) aw_message(error);
641    free(xfig);
642}
643
644static void canvas_to_printer(AW_window *aww, AWT_canvas *scr) {
645    GB_transaction  ta(scr->gb_main);
646    AW_root        *awr       = aww->get_root();
647    GB_ERROR        error     = NULp;
648    char           *dest      = NULp;
649    PrintDest       printdest = (PrintDest)awr->awar(AWAR_CANIO_DEST)->read_int();
650
651    switch (printdest) {
652        case PDEST_POSTSCRIPT: {
653            dest = AW_get_selected_fullname(awr, AWAR_CANIO_FILE_BASE);
654            FILE *out = fopen(dest, "w");
655            if (!out) error = GB_export_IO_error("writing", dest);
656            else fclose(out);
657            break;
658        }
659        default: {
660            char *name = GB_unique_filename("arb_print", "ps");
661            dest       = GB_create_tempfile(name);
662            free(name);
663
664            if (!dest) error = GB_await_error();
665            break;
666        }
667    }
668
669    if (!error) {
670        char *quotedDest = GBK_singlequote(dest);
671        char *xfig;
672        {
673            char *name = GB_unique_filename("arb_print", "xfig");
674            xfig       = GB_create_tempfile(name);
675            free(name);
676        }
677
678        arb_progress progress("Printing");
679        progress.subtitle("Exporting Data");
680
681        if (!xfig) error = GB_await_error();
682        if (!error) {
683            float border = awr->awar(AWAR_CANIO_BORDERSIZE)->read_float();
684            error        = canvas_to_xfig(scr, xfig, true, border);
685        }
686
687        if (!error) {
688            awt_assert(GB_is_privatefile(xfig, true));
689
690            // ----------------------------------------
691            progress.subtitle("Converting to Postscript");
692
693            {
694                bool   landscape     = awr->awar(AWAR_CANIO_LANDSCAPE)->read_int();
695                bool   useOverlap    = awr->awar(AWAR_CANIO_OVERLAP)->read_int();
696                double magnification = awr->awar(AWAR_CANIO_MAGNIFICATION)->read_int() * 0.01;
697                int    paper         = awr->awar(AWAR_CANIO_PAPER)->read_int();
698
699                const PaperFormat& format = knownPaperFormat[paper];
700
701                GBS_strstruct cmd(500);
702                cmd.cat("fig2dev");
703
704                cmd.cat(" -L ps"); // postscript output
705                if (useOverlap) {
706                    cmd.cat(" -M"); // generate multiple pages if needed
707                    cmd.cat(" -O"); // generate overlap (if printing to multiple pages)
708                }
709                cmd.nprintf(20, " -m %f", magnification);
710                cmd.cat(landscape ? " -l 0" : " -p 0");              // landscape or portrait
711
712                cmd.cat(" -z "); cmd.cat(format.get_fig2dev_val()); // paperformat
713
714                cmd.put(' '); cmd.cat(xfig);       // input
715                cmd.put(' '); cmd.cat(quotedDest); // output
716
717                error = GBK_system(cmd.get_data());
718            }
719
720            // if user saves to .ps -> no special file permissions are required
721            awt_assert(printdest == PDEST_POSTSCRIPT || GB_is_privatefile(dest, false));
722
723            if (!error) {
724                progress.subtitle("Printing");
725
726                switch (printdest) {
727                    case PDEST_PREVIEW: {
728                        GB_CSTR gs      = GB_getenvARB_GS();
729                        GB_CSTR command = GBS_global_string("(%s %s;rm -f %s) &", gs, dest, dest);
730                        error           = GBK_system(command);
731                        break;
732                    }
733                    case PDEST_POSTSCRIPT:
734                        break;
735
736                    case PDEST_PRINTER: {
737                        char *prt = awr->awar(AWAR_CANIO_PRINTER)->read_string();
738                        error     = GBK_system(GBS_global_string("%s %s", prt, dest));
739                        free(prt);
740                        GB_unlink_or_warn(dest, &error);
741                        break;
742                    }
743                }
744            }
745        }
746        if (xfig) {
747#if defined(DEBUG) && 0
748            // show intermediate xfig and unlink it
749            GBK_system(GBS_global_string("( xfig %s; rm %s) &", xfig, xfig));
750#else // !defined(DEBUG)
751            GB_unlink_or_warn(xfig, &error);
752#endif
753            free(xfig);
754        }
755        free(quotedDest);
756    }
757
758    free(dest);
759
760    if (error) aw_message(error);
761}
762
763// --------------------------------------------------------------------------------
764
765void AWT_popup_tree_export_window(AW_window *parent_win, AWT_canvas *scr) {
766    static AW_window_simple *aws = NULp;
767
768    AW_root *awr = parent_win->get_root();
769    create_fig_export_awars(awr);
770    resetFiletype(awr, "fig", "print.fig");
771
772    if (!aws) {
773        aws = new AW_window_simple;
774        aws->init(awr, "EXPORT_TREE_AS_XFIG", "EXPORT TREE TO XFIG");
775        aws->load_xfig("awt/export.fig");
776
777        aws->at("close"); aws->callback(AW_POPDOWN);
778        aws->create_button("CLOSE", "CLOSE", "C");
779
780        aws->at("help"); aws->callback(makeHelpCallback("tree2file.hlp"));
781        aws->create_button("HELP", "HELP", "H");
782
783        aws->label_length(15);
784
785        AW_create_standard_fileselection(aws, AWAR_CANIO_FILE_BASE);
786
787        aws->at("what");
788        aws->label("Clip at Screen");
789        aws->create_toggle_field(AWAR_CANIO_CLIP, 1);
790        aws->insert_toggle("#print/clipscreen.xpm", "S", 0);
791        aws->insert_toggle("#print/clipall.xpm", "A", 1);
792        aws->update_toggle_field();
793
794        aws->at("remove_root");
795        aws->label("Show Handles");
796        aws->create_toggle_field(AWAR_CANIO_HANDLES, 1);
797        aws->insert_toggle("#print/nohandles.xpm", "S", 0);
798        aws->insert_toggle("#print/handles.xpm", "A", 1);
799        aws->update_toggle_field();
800
801        aws->at("color");
802        aws->label("Export colors");
803        aws->create_toggle(AWAR_CANIO_COLOR);
804
805        aws->at("xfig"); aws->callback(makeWindowCallback(canvas_to_xfig_and_run_xfig, scr));
806        aws->create_autosize_button("START_XFIG", "EXPORT to XFIG", "X");
807    }
808
809    aws->activate();
810}
811
812void AWT_popup_sec_export_window(AW_window *parent_win, AWT_canvas *scr) {
813    static AW_window_simple *aws = NULp;
814
815    AW_root *awr = parent_win->get_root();
816    create_fig_export_awars(awr);
817    resetFiletype(awr, "fig", "print.fig");
818
819    if (!aws) {
820        aws = new AW_window_simple;
821        aws->init(awr, "EXPORT_TREE_AS_XFIG", "EXPORT STRUCTURE TO XFIG");
822        aws->load_xfig("awt/secExport.fig");
823
824        aws->at("close");
825        aws->callback(AW_POPDOWN);
826        aws->create_button("CLOSE", "CLOSE", "C");
827
828        aws->at("help");
829        aws->callback(makeHelpCallback("tree2file.hlp"));
830        aws->create_button("HELP", "HELP", "H");
831
832        aws->label_length(15);
833        AW_create_standard_fileselection(aws, AWAR_CANIO_FILE_BASE);
834
835        aws->at("what");
836        aws->label("Clip Options");
837        aws->create_option_menu(AWAR_CANIO_CLIP, true);
838        aws->insert_option("Export screen only", "s", 0);
839        aws->insert_default_option("Export complete structure", "c", 1);
840        aws->update_option_menu();
841
842        aws->at("color");
843        aws->label("Export colors");
844        aws->create_toggle(AWAR_CANIO_COLOR);
845
846        aws->at("xfig");
847        aws->callback(makeWindowCallback(canvas_to_xfig_and_run_xfig, scr));
848        aws->create_autosize_button("START_XFIG", "EXPORT to XFIG", "X");
849    }
850
851    aws->activate();
852}
853
854static void columns_changed_cb(AW_window *aww) { set_mag_from_psize(aww->get_root(), true); }
855static void rows_changed_cb(AW_window *aww) { set_mag_from_psize(aww->get_root(), false); }
856
857static void fit_pages_cb(AW_window *aww, int wanted_pages) {
858    AW_root *awr = aww->get_root();
859    if (wanted_pages<=0) {
860        wanted_pages = awr->awar(AWAR_CANIO_PAGES)->read_int();
861    }
862    fit_pages(awr, wanted_pages, true);
863}
864
865void AWT_popup_print_window(AW_window *parent_win, AWT_canvas *scr) {
866    AW_root                 *awr = parent_win->get_root();
867    static AW_window_simple *aws = NULp;
868
869    create_print_awars(awr, scr);
870    resetFiletype(awr, "ps", "print.ps");
871
872    if (!aws) {
873        aws = new AW_window_simple;
874        aws->init(awr, "PRINT_CANVAS", "PRINT GRAPHIC");
875        aws->load_xfig("awt/print.fig");
876
877        aws->at("close"); aws->callback(AW_POPDOWN);
878        aws->create_button("CLOSE", "CLOSE", "C");
879
880        aws->at("help"); aws->callback(makeHelpCallback("tree2prt.hlp"));
881        aws->create_button("HELP", "HELP", "H");
882
883        // -----------------------------
884        //      select what to print
885
886        aws->label_length(15);
887
888        aws->at("what");
889        aws->label("Clip at Screen");
890        aws->create_toggle_field(AWAR_CANIO_CLIP, 1);
891        aws->insert_toggle("#print/clipscreen.xpm", "S", 0);
892        aws->insert_toggle("#print/clipall.xpm", "A", 1);
893        aws->update_toggle_field();
894
895        aws->at("remove_root");
896        aws->label("Show Handles");
897        aws->create_toggle_field(AWAR_CANIO_HANDLES, 1);
898        aws->insert_toggle("#print/nohandles.xpm", "S", 0);
899        aws->insert_toggle("#print/handles.xpm", "A", 1);
900        aws->update_toggle_field();
901
902        aws->at("color");
903        aws->label("Export colors");
904        aws->create_toggle(AWAR_CANIO_COLOR);
905
906        // --------------------
907        //      page layout
908
909        aws->at("getsize");
910        aws->callback(makeWindowCallback(awt_print_tree_check_size, scr));
911        aws->create_autosize_button("GetGfxSize", "Get Graphic Size");
912
913        aws->button_length(6);
914        aws->at("gsizex"); aws->create_button(NULp, AWAR_CANIO_GFX_SX);
915        aws->at("gsizey"); aws->create_button(NULp, AWAR_CANIO_GFX_SY);
916        aws->at("osizex"); aws->create_button(NULp, AWAR_CANIO_OUT_SX);
917        aws->at("osizey"); aws->create_button(NULp, AWAR_CANIO_OUT_SY);
918
919        aws->at("magnification");
920        aws->create_input_field(AWAR_CANIO_MAGNIFICATION, 4);
921
922        aws->label_length(0);
923        aws->at("orientation");
924        aws->create_toggle_field(AWAR_CANIO_LANDSCAPE, 1);
925        aws->insert_toggle("#print/landscape.xpm", "L", 1);
926        aws->insert_toggle("#print/portrait.xpm",  "P", 0);
927        aws->update_toggle_field();
928
929        aws->at("bsize"); aws->create_input_field(AWAR_CANIO_BORDERSIZE, 4);
930
931        // -------------------
932        //      paper size
933
934        aws->at("psizex"); aws->create_input_field(AWAR_CANIO_PAPER_SX, 5);
935        aws->at("psizey"); aws->create_input_field(AWAR_CANIO_PAPER_SY, 5);
936
937        aws->at("paper");
938        aws->create_option_menu(AWAR_CANIO_PAPER, true);
939        aws->insert_default_option(knownPaperFormat[0].get_description(), "", 0);
940        for (int f = 1; f<int(ARRAY_ELEMS(knownPaperFormat)); ++f) {
941            const PaperFormat& format = knownPaperFormat[f];
942            aws->insert_option(format.get_description(), "", f);
943        }
944        aws->update_option_menu();
945
946        aws->at("usize"); aws->create_input_field(AWAR_CANIO_PAPER_USABLE, 4);
947
948
949        // -----------------------
950        //      multiple pages
951
952        aws->at("sizex");
953        aws->callback(columns_changed_cb); // @@@ used as INPUTFIELD_CB (see #559)
954        aws->create_input_field(AWAR_CANIO_PAGE_SX, 4);
955        aws->at("sizey");
956        aws->callback(rows_changed_cb); // @@@ used as INPUTFIELD_CB (see #559)
957        aws->create_input_field(AWAR_CANIO_PAGE_SY, 4);
958
959        aws->at("best_fit");
960        aws->callback(makeWindowCallback(fit_pages_cb, 0));
961        aws->create_autosize_button("fit_on", "Fit on");
962
963        aws->at("pages");
964        aws->create_input_field(AWAR_CANIO_PAGES, 3);
965
966        aws->at("plock");
967        aws->create_toggle(AWAR_CANIO_PAGELOCK);
968
969        aws->button_length(1);
970        {
971            char name[] = "p0";
972            for (int p = 1; p <= 9; ++p) {
973                name[1] = '0'+p; // at-label, macro-name and button-text
974                if (aws->at_ifdef(name)) {
975                    aws->at(name);
976                    aws->callback(makeWindowCallback(fit_pages_cb, p));
977                    aws->create_button(name, name+1);
978                }
979            }
980        }
981
982        aws->at("overlap");
983        aws->create_toggle(AWAR_CANIO_OVERLAP);
984        aws->at("amount");
985        aws->create_input_field(AWAR_CANIO_OVERLAP_PERCENT, 4);
986
987        aws->at("f2dbug");
988        aws->create_toggle(AWAR_CANIO_F2DBUG);
989
990        // --------------------
991        //      destination
992
993        aws->at("printto");
994        aws->label_length(12);
995        aws->label("Destination");
996        aws->create_toggle_field(AWAR_CANIO_DEST);
997        aws->insert_toggle("Printer",           "P", PDEST_PRINTER);
998        aws->insert_toggle("File (Postscript)", "F", PDEST_POSTSCRIPT);
999        aws->insert_toggle("Preview",           "V", PDEST_PREVIEW);
1000        aws->update_toggle_field();
1001
1002        aws->at("printer");
1003        aws->create_input_field(AWAR_CANIO_PRINTER, 16);
1004
1005        aws->at("filename");
1006        aws->create_input_field(AWAR_CANIO_FILE_NAME, 16);
1007
1008        aws->at("go");
1009        aws->highlight();
1010        aws->callback(makeWindowCallback(canvas_to_printer, scr));
1011        aws->create_autosize_button("PRINT", "PRINT", "P");
1012    }
1013
1014    awt_print_tree_check_size(NULp, scr);
1015    aws->activate();
1016}
Note: See TracBrowser for help on using the repository browser.