source: tags/ms_r18q1/WINDOW/AW_Xm.cxx

Last change on this file was 16961, checked in by westram, 6 years ago
  • partial merge from 'fix' into 'trunk'
    • refactored AW_device text output
      • reduces calls to strlen (using SizedCstr)
      • eliminated/modernized several parameters/functions (esp. in TextOverlayCallbacks)
  • adds: log:branches/fix@16939:16960
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.0 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_Xm.cxx                                         //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include <aw_Xm.hxx>
12
13#if defined(WARN_TODO)
14#warning change implementation of draw functions (read more)
15// * filter has to be checked early (in AW_device)
16// * functions shall use Position/LineVector/Rectangle only
17#endif
18
19using namespace AW;
20
21// ---------------------
22//      AW_device_Xm
23
24AW_DEVICE_TYPE AW_device_Xm::type() { return AW_DEVICE_SCREEN; }
25
26#define XDRAW_PARAM2(common)    (common)->get_display(), (common)->get_window_id()
27#define XDRAW_PARAM3(common,gc) XDRAW_PARAM2(common), (common)->get_GC(gc)
28
29bool AW_device_Xm::line_impl(int gc, const LineVector& Line, AW_bitset filteri) {
30    bool drawflag = false;
31    if (filteri & filter) {
32        LineVector transLine = transform(Line);
33        LineVector clippedLine;
34        drawflag = clip(transLine, clippedLine);
35        if (drawflag) {
36            XDrawLine(XDRAW_PARAM3(get_common(), gc),
37                      AW_INT(clippedLine.start().xpos()), AW_INT(clippedLine.start().ypos()),
38                      AW_INT(clippedLine.head().xpos()), AW_INT(clippedLine.head().ypos()));
39            AUTO_FLUSH(this);
40        }
41    }
42
43    return drawflag;
44}
45
46static bool AW_draw_string_on_screen(AW_device *device, int gc, const char *textBuffer, size_t textStart, size_t textLen, const AW::Position& pos, AW_CL /*cduser*/) {
47    // aw_assert(textLen <= strlen(textBuffer)); // already asserted by caller (text_overlay)
48
49    AW_device_Xm *device_xm = DOWNCAST(AW_device_Xm*, device);
50    AW::Position  POS(device_xm->transform(pos));
51
52    XDrawString(XDRAW_PARAM3(device_xm->get_common(), gc), AW_INT(POS.xpos()), AW_INT(POS.ypos()), textBuffer + textStart,  (int)textLen);
53    AUTO_FLUSH(device);
54
55    return true;
56}
57
58
59bool AW_device_Xm::text_impl(int gc, const SizedCstr& cstr, const AW::Position& pos, AW_pos alignment, AW_bitset filteri) {
60    return text_overlay(gc, cstr, pos, alignment, filteri, AW_draw_string_on_screen);
61}
62
63enum StippleType {
64    ST_UNDEFINED = -1,
65    FILLED_125   = 0,
66    FILLED_25,
67    FILLED_375,
68    FILLED_50,
69    FILLED_625,
70    FILLED_75,
71    FILLED_875,
72};
73
74const int PIXMAP_SIZE   = 8; // 8x8 stipple mask
75const int STIPPLE_TYPES = FILLED_875+1;
76
77static Pixmap getStipplePixmap(AW_common_Xm *common, StippleType stippleType) {
78    aw_assert(stippleType>=0 && stippleType<STIPPLE_TYPES);
79
80    static Pixmap pixmap[STIPPLE_TYPES];
81    static bool   initialized = false;
82
83    if (!initialized) {
84        for (int t = 0; t<STIPPLE_TYPES; ++t) {
85            static unsigned char stippleBits[STIPPLE_TYPES][PIXMAP_SIZE] = {
86                { 0x40, 0x08, 0x01, 0x20, 0x04, 0x80, 0x10, 0x02 }, // 12.5%
87                { 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 }, // 25%
88                { 0x15, 0xa2, 0x54, 0x8a, 0x51, 0x2a, 0x45, 0xa8 }, // 37.5%
89                { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }, // 50%
90                { 0xd5, 0xba, 0x57, 0xea, 0x5d, 0xab, 0x75, 0xae }, // 62.5%
91                { 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee }, // 75%
92                { 0xbf, 0xf7, 0xfe, 0xdf, 0xfb, 0x7f, 0xef, 0xfd }  // 87.5%
93            };
94            pixmap[t] = XCreateBitmapFromData(common->get_display(), common->get_window_id(), reinterpret_cast<const char *>(stippleBits[t]), PIXMAP_SIZE, PIXMAP_SIZE);
95        }
96        initialized = true;
97    }
98
99    return pixmap[stippleType];
100}
101
102AW_device_Xm::Fill_Style AW_device_Xm::setFillstyleForGreylevel(int gc, AW::FillStyle filled) {
103    // sets fillstyle and stipple for current greylevel of 'gc'
104
105    switch (filled.get_style()) {
106        case AW::FillStyle::SOLID: return FS_SOLID;
107        case AW::FillStyle::EMPTY: return FS_EMPTY;
108
109        case AW::FillStyle::SHADED:
110        case AW::FillStyle::SHADED_WITH_BORDER:
111            break; // detect using greylevel
112    }
113
114    AW_grey_level greylevel = get_grey_level(gc);
115
116    if (greylevel<0.0625) {
117        return FS_EMPTY;
118    }
119    if (greylevel<0.9375) { // otherwise draw solid
120        StippleType stippleType = ST_UNDEFINED;
121
122        if      (greylevel<0.1875) stippleType = FILLED_125;
123        else if (greylevel<0.3125) stippleType = FILLED_25;
124        else if (greylevel<0.4375) stippleType = FILLED_375;
125        else if (greylevel<0.5626) stippleType = FILLED_50;
126        else if (greylevel<0.6875) stippleType = FILLED_625;
127        else if (greylevel<0.8125) stippleType = FILLED_75;
128        else stippleType                       = FILLED_875;
129
130        AW_common_Xm *Common  = get_common();
131        Pixmap        stipple = getStipplePixmap(Common, stippleType);
132
133        Display *Disp = Common->get_display();
134        GC       xgc  = Common->get_GC(gc);
135
136        XSetFillRule(Disp, xgc,  WindingRule);
137        XSetStipple(Disp, xgc, stipple);
138        XSetFillStyle(Disp, xgc, FillStippled);
139
140        return FS_GREY;
141    }
142    return FS_SOLID;
143}
144void AW_device_Xm::resetFillstyleForGreylevel(int gc) {
145    // should be called after using setFillstyleForGreylevel (to undo XSetFillStyle)
146    // (Note: may be skipped if setFillstyleForGreylevel did not return FS_GREY)
147    XSetFillStyle(get_common()->get_display(), get_common()->get_GC(gc), FillSolid);
148}
149
150bool AW_device_Xm::box_impl(int gc, AW::FillStyle filled, const Rectangle& rect, AW_bitset filteri) {
151    bool drawflag = false;
152    if (filteri & filter) {
153        if (filled.is_empty()) {
154            drawflag = generic_box(gc, rect, filteri);
155        }
156        else {
157            Rectangle transRect = transform(rect);
158            Rectangle clippedRect;
159            drawflag = box_clip(transRect, clippedRect);
160            if (drawflag) {
161                Fill_Style fillStyle = setFillstyleForGreylevel(gc, filled);
162
163                if (fillStyle != FS_EMPTY) {
164                    XFillRectangle(XDRAW_PARAM3(get_common(), gc),
165                                   AW_INT(clippedRect.left()),
166                                   AW_INT(clippedRect.top()),
167                                   AW_INT(clippedRect.width())+1, // see aw_device.hxx@WORLD_vs_PIXEL
168                                   AW_INT(clippedRect.height())+1);
169
170                    if (fillStyle == FS_GREY) resetFillstyleForGreylevel(gc);
171                }
172                if (fillStyle != FS_SOLID && filled.get_style() != AW::FillStyle::SHADED) {
173                    // draw solid box-border (for empty and grey box)
174                    // (Note: using XDrawRectangle here is wrong)
175                    generic_box(gc, rect, filteri);
176                }
177                else {
178                    AUTO_FLUSH(this);
179                }
180            }
181        }
182    }
183    return drawflag;
184}
185
186bool AW_device_Xm::polygon_impl(int gc, AW::FillStyle filled, int npos, const AW::Position *pos, AW_bitset filteri) {
187    bool drawflag = false;
188    if (filteri & filter) {
189        if (filled.is_empty()) {
190            drawflag = generic_polygon(gc, npos, pos, filteri);
191        }
192        else {
193            Position *transPos = new Position[npos];
194            for (int p = 0; p<npos; ++p) {
195                transPos[p] = transform(pos[p]);
196            }
197
198            int           nclippedPos;
199            AW::Position *clippedPos = NULp;
200
201            drawflag = box_clip(npos, transPos, nclippedPos, clippedPos);
202            if (drawflag) {
203                Fill_Style fillStyle = setFillstyleForGreylevel(gc, filled);
204
205                if (fillStyle != FS_EMPTY) {
206                    XPoint *xpos = new XPoint[nclippedPos];
207
208                    for (int p = 0; p<nclippedPos; ++p) {
209                        xpos[p].x = AW_INT(clippedPos[p].xpos());
210                        xpos[p].y = AW_INT(clippedPos[p].ypos());
211                    }
212
213                    XFillPolygon(XDRAW_PARAM3(get_common(), gc),
214                                 xpos,
215                                 nclippedPos,
216                                 // Complex,
217                                 // Nonconvex,
218                                 Convex,
219                                 CoordModeOrigin);
220
221                    if (fillStyle == FS_GREY) resetFillstyleForGreylevel(gc);
222                    delete [] xpos;
223                }
224                if (fillStyle != FS_SOLID && filled.get_style() != AW::FillStyle::SHADED) {
225                    // draw solid polygon-border (for empty and grey polygon)
226                    // (Note: using XDrawRectangle here is wrong)
227                    generic_polygon(gc, npos, pos, filteri);
228                }
229                else {
230                    AUTO_FLUSH(this);
231                }
232            }
233
234            delete [] clippedPos;
235            delete [] transPos;
236        }
237    }
238    return drawflag;
239}
240
241bool AW_device_Xm::circle_impl(int gc, AW::FillStyle filled, const AW::Position& center, const AW::Vector& radius, AW_bitset filteri) {
242    aw_assert(radius.x()>0 && radius.y()>0);
243    return arc_impl(gc, filled, center, radius, 0, 360, filteri);
244}
245
246bool AW_device_Xm::arc_impl(int gc, AW::FillStyle filled, const AW::Position& center, const AW::Vector& radius, int start_degrees, int arc_degrees, AW_bitset filteri) {
247    // degrees start at east side of unit circle,
248    // but orientation is clockwise (because ARBs y-coordinate grows downwards)
249
250    bool drawflag = false;
251    if (filteri & filter) {
252        Rectangle Box(center-radius, center+radius);
253        Rectangle screen_box = transform(Box);
254
255        drawflag = !is_outside_clip(screen_box);
256        if (drawflag) {
257            int             width  = AW_INT(screen_box.width());
258            int             height = AW_INT(screen_box.height());
259            const Position& ulc    = screen_box.upper_left_corner();
260            int             xl     = AW_INT(ulc.xpos());
261            int             yl     = AW_INT(ulc.ypos());
262
263            aw_assert(arc_degrees >= -360 && arc_degrees <= 360);
264
265            // ARB -> X
266            start_degrees = -start_degrees;
267            arc_degrees   = -arc_degrees;
268
269            while (start_degrees<0) start_degrees += 360;
270
271            if (filled.is_empty()) {
272                XDrawArc(XDRAW_PARAM3(get_common(), gc), xl, yl, width, height, 64*start_degrees, 64*arc_degrees);
273            }
274            else {
275                aw_assert(!filled.is_shaded()); // @@@ shading not implemented for arcs (yet)
276                XFillArc(XDRAW_PARAM3(get_common(), gc), xl, yl, width, height, 64*start_degrees, 64*arc_degrees);
277            }
278            AUTO_FLUSH(this);
279        }
280    }
281    return drawflag;
282}
283
284void AW_device_Xm::clear(AW_bitset filteri) {
285    if (filteri & filter) {
286        XClearWindow(XDRAW_PARAM2(get_common()));
287        AUTO_FLUSH(this);
288    }
289}
290
291void AW_device_Xm::clear_part(const Rectangle& rect, AW_bitset filteri) {
292    if (filteri & filter) {
293        Rectangle transRect = transform(rect);
294        Rectangle clippedRect;
295        bool drawflag = box_clip(transRect, clippedRect);
296        if (drawflag) {
297            XClearArea(XDRAW_PARAM2(get_common()),
298                       AW_INT(clippedRect.left()),
299                       AW_INT(clippedRect.top()),
300                       AW_INT(clippedRect.width())+1, // see aw_device.hxx@WORLD_vs_PIXEL
301                       AW_INT(clippedRect.height())+1,
302                       False);
303            AUTO_FLUSH(this);
304        }
305    }
306}
307
308void AW_device_Xm::flush() {
309    XFlush(get_common()->get_display());
310}
311
312void AW_device_Xm::move_region(AW_pos src_x, AW_pos src_y, AW_pos width, AW_pos height, AW_pos dest_x, AW_pos dest_y) {
313    int gc = 0;
314    XCopyArea(get_common()->get_display(), get_common()->get_window_id(), get_common()->get_window_id(), get_common()->get_GC(gc),
315              AW_INT(src_x), AW_INT(src_y), AW_INT(width), AW_INT(height),
316              AW_INT(dest_x), AW_INT(dest_y));
317    AUTO_FLUSH(this);
318}
319
Note: See TracBrowser for help on using the repository browser.