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