source: tags/ms_r16q2/WINDOW/AW_print.cxx

Last change on this file was 14885, checked in by westram, 8 years ago
  • add short font descriptions to motif version
    • display them on font-selection-buttons
    • runtime check vs duplicate names/specs (DEBUG)
  • move font interface from aw_root.hxx → aw_xfont.hxx (=restrict use to WINDOW library)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_print.cxx                                      //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "aw_root.hxx"
12#include "aw_common.hxx"
13#include "aw_xfont.hxx"
14
15#include <arb_msg.h>
16
17using namespace AW;
18
19const double dpi_screen2printer = double(DPI_PRINTER)/DPI_SCREEN;
20
21inline double screen2printer(double val) { return val*dpi_screen2printer; }
22inline int print_pos(AW_pos screen_pos) { return AW_INT(screen2printer(screen_pos)); }
23
24AW_DEVICE_TYPE AW_device_print::type() { return AW_DEVICE_PRINTER; }
25
26bool AW_device_print::line_impl(int gc, const LineVector& Line, AW_bitset filteri) {
27    bool drawflag = false;
28    if (filteri & filter) {
29        LineVector transLine = transform(Line);
30        LineVector clippedLine;
31        drawflag = clip(transLine, clippedLine);
32
33        if (drawflag) {
34            const AW_GC *gcm        = get_common()->map_gc(gc);
35            int          line_width = gcm->get_line_width();
36
37            int    line_mode = 0;
38            double gap_ratio = 0.0;
39            switch (gcm->get_line_style()) {
40                case AW_SOLID: /* use defaults from above*/ break;
41                case AW_DASHED:  line_mode = 1; gap_ratio = 4.0; break;
42                case AW_DOTTED:  line_mode = 2; gap_ratio = 2.0; break;
43            }
44
45            aw_assert(out);     // file has to be good!
46
47            // type, subtype, style, thickness, pen_color,
48            // fill_color(new), depth, pen_style, area_fill, style_val,
49            // join_style(new), cap_style(new), radius, forward_arrow,
50            // backward_arrow, npoints
51            fprintf(out, "2 1 %d %d %d 0 0 0 0 %5.3f 0 1 0 0 0 2\n\t%d %d %d %d\n",
52                    line_mode,
53                    AW_INT(line_width),
54                    find_color_idx(gcm->get_last_fg_color()),
55                    gap_ratio,
56                    print_pos(clippedLine.xpos()),
57                    print_pos(clippedLine.ypos()),
58                    print_pos(clippedLine.head().xpos()),
59                    print_pos(clippedLine.head().ypos()));
60        }
61    }
62    return drawflag;
63}
64
65bool AW_device_print::invisible_impl(const AW::Position& pos, AW_bitset filteri) {
66    bool drawflag = false;
67    if (filteri & filter) {
68        Position trans = transform(pos);
69
70        drawflag = !is_outside_clip(trans);
71        if (drawflag) {
72            fprintf(out, "2 1 0 1 7 7 50 -1 -1 0.000 0 0 -1 0 0 1\n\t%d %d\n",
73                    print_pos(trans.xpos()),
74                    print_pos(trans.ypos()));
75        }
76    }
77    return drawflag;
78}
79
80static bool AW_draw_string_on_printer(AW_device *devicei, int gc, const char *str, size_t /* opt_strlen */, size_t start, size_t size,
81                                      AW_pos x, AW_pos y, AW_pos /*opt_ascent*/, AW_pos /*opt_descent*/,
82                                      AW_CL /*cduser*/)
83{
84    AW_pos           X, Y;
85    AW_device_print *device = (AW_device_print *)devicei;
86    AW_common       *common = device->get_common();
87    const AW_GC     *gcm    = common->map_gc(gc);
88
89    device->transform(x, y, X, Y);
90    char *pstr = strdup(str+start);
91    if (size < strlen(pstr)) pstr[size] = 0;
92    else size  = strlen(pstr);
93    size_t i;
94    for (i=0; i<size; i++) {
95        if (pstr[i] < ' ') pstr[i] = '?';
96    }
97    int fontnr = AW_font_2_xfig(gcm->get_fontnr());
98    if (fontnr<0) fontnr = - fontnr;
99    if (str[0]) {
100        // 4=string 0=left color depth penstyle font font_size angle
101        // font_flags height length x y string
102        // (font/fontsize and color/depth have been switched from format
103        // 2.1 to 3.2
104        fprintf(device->get_FILE(), "4 0 %d 0 0 %d %d 0.000 4 %d %d %d %d ",
105                device->find_color_idx(gcm->get_last_fg_color()),
106                fontnr,
107                gcm->get_fontsize(),
108                (int)gcm->get_font_limits().height,
109                device->get_string_size(gc, str, 0),
110                print_pos(X),
111                print_pos(Y));
112        char *p;
113        for (p = pstr; *p; p++) {
114            if (*p >= 32) putc(*p, device->get_FILE());
115        }
116        fprintf(device->get_FILE(), "\\001\n");
117    }
118    free(pstr);
119    return true;
120}
121
122#define DATA_COLOR_OFFSET 32
123
124GB_ERROR AW_device_print::open(const char *path) {
125    if (out) return "You cannot reopen a device";
126
127    out = fopen(path, "w");
128    if (!out) return GB_IO_error("writing", path);
129
130    fprintf(out,
131            "#FIG 3.2\n"   // version
132            "Landscape\n"  // "Portrait"
133            "Center\n"     // "Flush Left"
134            "Metric\n"     // "Inches"
135            "A4\n"         // papersize
136            "100.0\n"      // export&print magnification %
137            "Single\n"     // Single/Multiple Pages
138            "-3\n"         // background = transparent for gif export
139            "%i 2\n"       // dpi, 2  = origin in upper left corner
140            , DPI_PRINTER);
141
142    if (color_mode) {
143        for (int i=0; i<get_common()->get_data_color_size(); i++) {
144            unsigned long col = get_common()->get_data_color(i);
145            if (col != (unsigned long)AW_NO_COLOR) fprintf(out, "0 %d #%06lx\n", i+DATA_COLOR_OFFSET, col);
146        }
147    }
148
149    return 0;
150}
151
152int AW_common::find_data_color_idx(AW_rgb color) const {
153    for (int i=0; i<data_colors_size; i++) {
154        if (color == data_colors[i]) {
155            return i;
156        }
157    }
158    return -1;
159}
160
161int AW_device_print::find_color_idx(AW_rgb color) {
162    int idx = -1;
163    if (color_mode) {
164        idx = get_common()->find_data_color_idx(color);
165        if (idx >= 0) idx += DATA_COLOR_OFFSET;
166    }
167    return idx;
168}
169
170void AW_device_print::set_color_mode(bool mode) {
171    color_mode=mode;
172}
173
174void AW_device_print::close() {
175    if (out) fclose(out);
176    out = 0;
177}
178
179
180bool AW_device_print::text_impl(int gc, const char *str, const Position& pos, AW_pos alignment, AW_bitset filteri, long opt_strlen) {
181    return text_overlay(gc, str, opt_strlen, pos, alignment, filteri, (AW_CL)this, 0.0, 0.0, AW_draw_string_on_printer);
182}
183
184bool AW_device_print::box_impl(int gc, AW::FillStyle filled, const Rectangle& rect, AW_bitset filteri) {
185    bool drawflag = false;
186    if (filter & filteri) {
187        if (filled.somehow()) {
188            Position q[4];
189            q[0] = rect.upper_left_corner();
190            q[1] = rect.upper_right_corner();
191            q[2] = rect.lower_right_corner();
192            q[3] = rect.lower_left_corner();
193
194            drawflag = polygon(gc, filled, 4, q, filteri);
195        }
196        else {
197            drawflag = generic_box(gc, rect, filteri);
198        }
199    }
200    return drawflag;
201}
202
203bool AW_device_print::circle_impl(int gc, AW::FillStyle filled, const Position& center, const AW::Vector& radius, AW_bitset filteri) {
204    bool drawflag = false;
205    if (filteri & filter) {
206        aw_assert(radius.x()>0 && radius.y()>0);
207        Rectangle Box(center-radius, center+radius);
208        Rectangle screen_box = transform(Box);
209        Rectangle clipped_box;
210        drawflag          = box_clip(screen_box, clipped_box);
211        bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
212
213        drawflag = drawflag && half_visible;
214        // @@@ correct behavior would be to draw an arc if only partly visible
215
216        if (drawflag) {
217            const AW_GC *gcm = get_common()->map_gc(gc);
218
219            // force into clipped_box (hack):
220            Position Center        = clipped_box.centroid();
221            Vector   screen_radius = clipped_box.diagonal()/2;
222
223            int cx = print_pos(Center.xpos());
224            int cy = print_pos(Center.ypos());
225            int rx = print_pos(screen_radius.x());
226            int ry = print_pos(screen_radius.y());
227
228            {
229                int subtype = (rx == ry) ? 3 : 1; // 3(circle) 1(ellipse)
230                subtype     = 3; // @@@ remove after refactoring
231                fprintf(out, "1 %d  ", subtype);  // type + subtype:
232            }
233
234            {
235                int colorIdx = find_color_idx(gcm->get_last_fg_color());
236                int fill_color, area_fill;
237                if (filled.somehow()) {
238                    fill_color = colorIdx;
239                    area_fill  = AW_INT(20+20*gcm->get_grey_level());    // 20 = full saturation; 40 = white;
240                }
241                else {
242                    fill_color = area_fill = -1;
243                }
244                int line_width = gcm->get_line_width();
245
246                fprintf(out, "%d %d ", AW_SOLID, line_width);   // line_style + line_width
247                fprintf(out, "%d %d 0 ", colorIdx, fill_color); // pen_color + fill_color + depth
248                fprintf(out, "0 %d ", area_fill);               // pen_style + area_fill (20 = full color, 40 = white)
249                fputs("0.000 1 0.0000 ", out);                  // style_val + direction + angle (x-axis)
250            }
251
252            fprintf(out, "%d %d ", cx, cy); // center
253            fprintf(out, "%d %d ", rx, ry); // radius
254            fprintf(out, "%d %d ", cx, cy); // start
255            fprintf(out, "%d %d\n", print_pos(Center.xpos()+screen_radius.x()), cy); // end
256        }
257    }
258    return drawflag;
259}
260
261bool AW_device_print::arc_impl(int gc, AW::FillStyle filled, const AW::Position& center, const AW::Vector& radius, int start_degrees, int arc_degrees, AW_bitset filteri) {
262    bool drawflag = false;
263    if (filteri && filter) {
264        aw_assert(radius.x()>0 && radius.y()>0);
265        Rectangle Box(center-radius, center+radius);
266        Rectangle screen_box = transform(Box);
267        Rectangle clipped_box;
268        drawflag          = box_clip(screen_box, clipped_box);
269        bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
270
271        drawflag = drawflag && half_visible;
272        // @@@ correct behavior would be to draw an arc if only partly visible
273
274        if (drawflag) {
275            const AW_GC *gcm = get_common()->map_gc(gc);
276
277            // force into clipped_box (hack):
278            Position Center        = clipped_box.centroid();
279            Vector   screen_radius = clipped_box.diagonal()/2;
280
281            int cx = print_pos(Center.xpos());
282            int cy = print_pos(Center.ypos());
283            int rx = print_pos(screen_radius.x());
284            int ry = print_pos(screen_radius.y());
285
286            bool use_spline = (rx != ry); // draw interpolated spline for ellipsoid arcs
287
288            // fputs(use_spline ? "3 2 " : "5 1 ", out);  // type + subtype:
289            fputs(use_spline ? "3 4 " : "5 1 ", out);  // type + subtype:
290
291            {
292                int colorIdx = find_color_idx(gcm->get_last_fg_color());
293                int fill_color, area_fill;
294
295                if (filled.somehow()) {
296                    fill_color = colorIdx;
297                    area_fill  = AW_INT(20+20*gcm->get_grey_level());    // 20 = full saturation; 40 = white;
298                }
299                else {
300                    fill_color = area_fill = -1;
301                }
302                int line_width = gcm->get_line_width();
303
304                fprintf(out, "%d %d ", AW_SOLID, line_width);   // line_style + line_width
305                fprintf(out, "%d %d 0 ", colorIdx, fill_color); // pen_color + fill_color + depth
306                fprintf(out, "0 %d ", area_fill);               // pen_style + area_fill (20 = full color, 40 = white)
307                fputs("0.000 1 ", out);                         // style_val + cap_style
308                if (!use_spline) fputs("1 ", out);              // direction
309                fputs("0 0 ", out);                             // 2 arrows
310            }
311
312            Angle a0(Angle::deg2rad*start_degrees);
313            Angle a1(Angle::deg2rad*(start_degrees+arc_degrees));
314
315            if (use_spline) {
316                const int MAX_ANGLE_STEP = 45; // degrees
317
318                int steps = (abs(arc_degrees)-1)/MAX_ANGLE_STEP+1;
319                Angle step(Angle::deg2rad*double(arc_degrees)/steps);
320
321                fprintf(out, "%d\n\t", steps+1); // npoints
322
323                double rmax, x_factor, y_factor;
324                if (rx>ry) {
325                    rmax     = rx;
326                    x_factor = 1.0;
327                    y_factor = double(ry)/rx;
328                }
329                else {
330                    rmax     = ry;
331                    x_factor = double(rx)/ry;
332                    y_factor = 1.0;
333                }
334
335                for (int n = 0; n <= steps; ++n) {
336                    Vector   toCircle  = a0.normal()*rmax;
337                    Vector   toEllipse(toCircle.x()*x_factor, toCircle.y()*y_factor);
338                    Position onEllipse = Center+toEllipse;
339
340                    int x = print_pos(onEllipse.xpos());
341                    int y = print_pos(onEllipse.ypos());
342
343                    fprintf(out, " %d %d", x, y);
344
345                    if (n<steps) {
346                        if (n == steps-1) a0 = a1;
347                        else              a0 += step;
348                    }
349                }
350                fputs("\n\t", out);
351                for (int n = 0; n <= steps; ++n) {
352                    // -1 = interpolate; 0 = discontinuity; 1 = approximate
353                    fprintf(out, " %d", (n == 0 || n == steps) ? 0 : -1);
354                }
355                fputc('\n', out);
356            }
357            else {
358                fprintf(out, "%d %d ", cx, cy); // center
359
360                Angle am(Angle::deg2rad*(start_degrees+arc_degrees*0.5));
361
362                double   r  = screen_radius.x();
363                Position p0 = Center+a0.normal()*r;
364                Position pm = Center+am.normal()*r;
365                Position p1 = Center+a1.normal()*r;
366
367                fprintf(out, "%d %d ",  print_pos(p0.xpos()), print_pos(p0.ypos()));
368                fprintf(out, "%d %d ",  print_pos(pm.xpos()), print_pos(pm.ypos()));
369                fprintf(out, "%d %d\n", print_pos(p1.xpos()), print_pos(p1.ypos()));
370            }
371        }
372    }
373    return drawflag;
374}
375
376bool AW_device_print::polygon_impl(int gc, AW::FillStyle filled, int npos, const Position *pos, AW_bitset filteri) {
377    bool drawflag = false;
378    if (filter & filteri) {
379        drawflag = generic_polygon(gc, npos, pos, filteri);
380        if (drawflag) { // line visible -> area fill needed
381            const AW_GC *gcm = get_common()->map_gc(gc);
382
383            short greylevel             = (short)(gcm->get_grey_level()*22);
384            if (greylevel>21) greylevel = 21;
385
386            int line_width = gcm->get_line_width();
387
388            fprintf(out, "2 3 0 %d %d -1 0 0 %d 0.000 0 0 -1 0 0 %d\n",
389                    line_width, find_color_idx(gcm->get_last_fg_color()), greylevel, npos+1);
390
391            // @@@ method used here for clipping leads to wrong results,
392            // since group border (drawn by generic_polygon() above) is clipped correctly,
393            // but filled content is clipped different.
394            //
395            // fix: clip the whole polygon before drawing border
396
397            for (int i=0; i <= npos; i++) {
398                int j = i == npos ? 0 : i; // print pos[0] after pos[n-1]
399
400                Position transPos = transform(pos[j]);
401                Position clippedPos;
402                ASSERT_RESULT(bool, true, force_into_clipbox(transPos, clippedPos));
403                fprintf(out, "   %d %d\n", print_pos(clippedPos.xpos()), print_pos(clippedPos.ypos()));
404            }
405        }
406    }
407    return drawflag;
408}
Note: See TracBrowser for help on using the repository browser.