diff options
Diffstat (limited to 'apps/plugins/puzzles/src/drawing.c')
-rw-r--r-- | apps/plugins/puzzles/src/drawing.c | 196 |
1 files changed, 120 insertions, 76 deletions
diff --git a/apps/plugins/puzzles/src/drawing.c b/apps/plugins/puzzles/src/drawing.c index 2c8816c31a..a754b068f3 100644 --- a/apps/plugins/puzzles/src/drawing.c +++ b/apps/plugins/puzzles/src/drawing.c | |||
@@ -42,9 +42,12 @@ struct print_colour { | |||
42 | float grey; | 42 | float grey; |
43 | }; | 43 | }; |
44 | 44 | ||
45 | struct drawing { | 45 | typedef struct drawing_internal { |
46 | const drawing_api *api; | 46 | /* we implement data hiding by casting `struct drawing*` pointers |
47 | void *handle; | 47 | * to `struct drawing_internal*` */ |
48 | struct drawing pub; | ||
49 | |||
50 | /* private data */ | ||
48 | struct print_colour *colours; | 51 | struct print_colour *colours; |
49 | int ncolours, coloursize; | 52 | int ncolours, coloursize; |
50 | float scale; | 53 | float scale; |
@@ -52,53 +55,70 @@ struct drawing { | |||
52 | * this may set it to NULL. */ | 55 | * this may set it to NULL. */ |
53 | midend *me; | 56 | midend *me; |
54 | char *laststatus; | 57 | char *laststatus; |
55 | }; | 58 | } drawing_internal; |
59 | |||
60 | #define PRIVATE_CAST(dr) ((drawing_internal*)(dr)) | ||
61 | #define PUBLIC_CAST(dri) ((drawing*)(dri)) | ||
62 | |||
63 | /* See puzzles.h for a description of the version number. */ | ||
64 | #define DRAWING_API_VERSION 1 | ||
56 | 65 | ||
57 | drawing *drawing_new(const drawing_api *api, midend *me, void *handle) | 66 | drawing *drawing_new(const drawing_api *api, midend *me, void *handle) |
58 | { | 67 | { |
59 | drawing *dr = snew(drawing); | 68 | if(api->version != DRAWING_API_VERSION) { |
60 | dr->api = api; | 69 | fatal("Drawing API version mismatch: expected: %d, actual: %d\n", DRAWING_API_VERSION, api->version); |
61 | dr->handle = handle; | 70 | /* shouldn't get here */ |
62 | dr->colours = NULL; | 71 | return NULL; |
63 | dr->ncolours = dr->coloursize = 0; | 72 | } |
64 | dr->scale = 1.0F; | 73 | |
65 | dr->me = me; | 74 | drawing_internal *dri = snew(drawing_internal); |
66 | dr->laststatus = NULL; | 75 | dri->pub.api = api; |
67 | return dr; | 76 | dri->pub.handle = handle; |
77 | dri->colours = NULL; | ||
78 | dri->ncolours = dri->coloursize = 0; | ||
79 | dri->scale = 1.0F; | ||
80 | dri->me = me; | ||
81 | dri->laststatus = NULL; | ||
82 | return PUBLIC_CAST(dri); | ||
68 | } | 83 | } |
69 | 84 | ||
70 | void drawing_free(drawing *dr) | 85 | void drawing_free(drawing *dr) |
71 | { | 86 | { |
72 | sfree(dr->laststatus); | 87 | drawing_internal *dri = PRIVATE_CAST(dr); |
73 | sfree(dr->colours); | 88 | sfree(dri->laststatus); |
74 | sfree(dr); | 89 | sfree(dri->colours); |
90 | sfree(dri); | ||
75 | } | 91 | } |
76 | 92 | ||
77 | void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, | 93 | void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, |
78 | int align, int colour, const char *text) | 94 | int align, int colour, const char *text) |
79 | { | 95 | { |
80 | dr->api->draw_text(dr->handle, x, y, fonttype, fontsize, align, | 96 | drawing_internal *dri = PRIVATE_CAST(dr); |
81 | colour, text); | 97 | dri->pub.api->draw_text(dr, x, y, fonttype, fontsize, align, |
98 | colour, text); | ||
82 | } | 99 | } |
83 | 100 | ||
84 | void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) | 101 | void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) |
85 | { | 102 | { |
86 | dr->api->draw_rect(dr->handle, x, y, w, h, colour); | 103 | drawing_internal *dri = PRIVATE_CAST(dr); |
104 | dri->pub.api->draw_rect(dr, x, y, w, h, colour); | ||
87 | } | 105 | } |
88 | 106 | ||
89 | void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) | 107 | void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) |
90 | { | 108 | { |
91 | dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour); | 109 | drawing_internal *dri = PRIVATE_CAST(dr); |
110 | dri->pub.api->draw_line(dr, x1, y1, x2, y2, colour); | ||
92 | } | 111 | } |
93 | 112 | ||
94 | void draw_thick_line(drawing *dr, float thickness, | 113 | void draw_thick_line(drawing *dr, float thickness, |
95 | float x1, float y1, float x2, float y2, int colour) | 114 | float x1, float y1, float x2, float y2, int colour) |
96 | { | 115 | { |
116 | drawing_internal *dri = PRIVATE_CAST(dr); | ||
97 | if (thickness < 1.0F) | 117 | if (thickness < 1.0F) |
98 | thickness = 1.0F; | 118 | thickness = 1.0F; |
99 | if (dr->api->draw_thick_line) { | 119 | if (dri->pub.api->draw_thick_line) { |
100 | dr->api->draw_thick_line(dr->handle, thickness, | 120 | dri->pub.api->draw_thick_line(dr, thickness, |
101 | x1, y1, x2, y2, colour); | 121 | x1, y1, x2, y2, colour); |
102 | } else { | 122 | } else { |
103 | /* We'll fake it up with a filled polygon. The tweak to the | 123 | /* We'll fake it up with a filled polygon. The tweak to the |
104 | * thickness empirically compensates for rounding errors, because | 124 | * thickness empirically compensates for rounding errors, because |
@@ -117,59 +137,67 @@ void draw_thick_line(drawing *dr, float thickness, | |||
117 | p[5] = y2 - tvhatx; | 137 | p[5] = y2 - tvhatx; |
118 | p[6] = x1 + tvhaty; | 138 | p[6] = x1 + tvhaty; |
119 | p[7] = y1 - tvhatx; | 139 | p[7] = y1 - tvhatx; |
120 | dr->api->draw_polygon(dr->handle, p, 4, colour, colour); | 140 | dri->pub.api->draw_polygon(dr, p, 4, colour, colour); |
121 | } | 141 | } |
122 | } | 142 | } |
123 | 143 | ||
124 | void draw_polygon(drawing *dr, const int *coords, int npoints, | 144 | void draw_polygon(drawing *dr, const int *coords, int npoints, |
125 | int fillcolour, int outlinecolour) | 145 | int fillcolour, int outlinecolour) |
126 | { | 146 | { |
127 | dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour, | 147 | drawing_internal *dri = PRIVATE_CAST(dr); |
128 | outlinecolour); | 148 | dri->pub.api->draw_polygon(dr, coords, npoints, fillcolour, |
149 | outlinecolour); | ||
129 | } | 150 | } |
130 | 151 | ||
131 | void draw_circle(drawing *dr, int cx, int cy, int radius, | 152 | void draw_circle(drawing *dr, int cx, int cy, int radius, |
132 | int fillcolour, int outlinecolour) | 153 | int fillcolour, int outlinecolour) |
133 | { | 154 | { |
134 | dr->api->draw_circle(dr->handle, cx, cy, radius, fillcolour, | 155 | drawing_internal *dri = PRIVATE_CAST(dr); |
135 | outlinecolour); | 156 | dri->pub.api->draw_circle(dr, cx, cy, radius, fillcolour, |
157 | outlinecolour); | ||
136 | } | 158 | } |
137 | 159 | ||
138 | void draw_update(drawing *dr, int x, int y, int w, int h) | 160 | void draw_update(drawing *dr, int x, int y, int w, int h) |
139 | { | 161 | { |
140 | if (dr->api->draw_update) | 162 | drawing_internal *dri = PRIVATE_CAST(dr); |
141 | dr->api->draw_update(dr->handle, x, y, w, h); | 163 | if (dri->pub.api->draw_update) |
164 | dri->pub.api->draw_update(dr, x, y, w, h); | ||
142 | } | 165 | } |
143 | 166 | ||
144 | void clip(drawing *dr, int x, int y, int w, int h) | 167 | void clip(drawing *dr, int x, int y, int w, int h) |
145 | { | 168 | { |
146 | dr->api->clip(dr->handle, x, y, w, h); | 169 | drawing_internal *dri = PRIVATE_CAST(dr); |
170 | dri->pub.api->clip(dr, x, y, w, h); | ||
147 | } | 171 | } |
148 | 172 | ||
149 | void unclip(drawing *dr) | 173 | void unclip(drawing *dr) |
150 | { | 174 | { |
151 | dr->api->unclip(dr->handle); | 175 | drawing_internal *dri = PRIVATE_CAST(dr); |
176 | dri->pub.api->unclip(dr); | ||
152 | } | 177 | } |
153 | 178 | ||
154 | void start_draw(drawing *dr) | 179 | void start_draw(drawing *dr) |
155 | { | 180 | { |
156 | dr->api->start_draw(dr->handle); | 181 | drawing_internal *dri = PRIVATE_CAST(dr); |
182 | dri->pub.api->start_draw(dr); | ||
157 | } | 183 | } |
158 | 184 | ||
159 | void end_draw(drawing *dr) | 185 | void end_draw(drawing *dr) |
160 | { | 186 | { |
161 | dr->api->end_draw(dr->handle); | 187 | drawing_internal *dri = PRIVATE_CAST(dr); |
188 | dri->pub.api->end_draw(dr); | ||
162 | } | 189 | } |
163 | 190 | ||
164 | char *text_fallback(drawing *dr, const char *const *strings, int nstrings) | 191 | char *text_fallback(drawing *dr, const char *const *strings, int nstrings) |
165 | { | 192 | { |
193 | drawing_internal *dri = PRIVATE_CAST(dr); | ||
166 | int i; | 194 | int i; |
167 | 195 | ||
168 | /* | 196 | /* |
169 | * If the drawing implementation provides one of these, use it. | 197 | * If the drawing implementation provides one of these, use it. |
170 | */ | 198 | */ |
171 | if (dr && dr->api->text_fallback) | 199 | if (dr && dri->pub.api->text_fallback) |
172 | return dr->api->text_fallback(dr->handle, strings, nstrings); | 200 | return dri->pub.api->text_fallback(dr, strings, nstrings); |
173 | 201 | ||
174 | /* | 202 | /* |
175 | * Otherwise, do the simple thing and just pick the first string | 203 | * Otherwise, do the simple thing and just pick the first string |
@@ -196,18 +224,19 @@ char *text_fallback(drawing *dr, const char *const *strings, int nstrings) | |||
196 | 224 | ||
197 | void status_bar(drawing *dr, const char *text) | 225 | void status_bar(drawing *dr, const char *text) |
198 | { | 226 | { |
227 | drawing_internal *dri = PRIVATE_CAST(dr); | ||
199 | char *rewritten; | 228 | char *rewritten; |
200 | 229 | ||
201 | if (!dr->api->status_bar) | 230 | if (!dri->pub.api->status_bar) |
202 | return; | 231 | return; |
203 | 232 | ||
204 | assert(dr->me); | 233 | assert(dri->me); |
205 | 234 | ||
206 | rewritten = midend_rewrite_statusbar(dr->me, text); | 235 | rewritten = midend_rewrite_statusbar(dri->me, text); |
207 | if (!dr->laststatus || strcmp(rewritten, dr->laststatus)) { | 236 | if (!dri->laststatus || strcmp(rewritten, dri->laststatus)) { |
208 | dr->api->status_bar(dr->handle, rewritten); | 237 | dri->pub.api->status_bar(dr, rewritten); |
209 | sfree(dr->laststatus); | 238 | sfree(dri->laststatus); |
210 | dr->laststatus = rewritten; | 239 | dri->laststatus = rewritten; |
211 | } else { | 240 | } else { |
212 | sfree(rewritten); | 241 | sfree(rewritten); |
213 | } | 242 | } |
@@ -215,74 +244,85 @@ void status_bar(drawing *dr, const char *text) | |||
215 | 244 | ||
216 | blitter *blitter_new(drawing *dr, int w, int h) | 245 | blitter *blitter_new(drawing *dr, int w, int h) |
217 | { | 246 | { |
218 | return dr->api->blitter_new(dr->handle, w, h); | 247 | drawing_internal *dri = PRIVATE_CAST(dr); |
248 | return dri->pub.api->blitter_new(dr, w, h); | ||
219 | } | 249 | } |
220 | 250 | ||
221 | void blitter_free(drawing *dr, blitter *bl) | 251 | void blitter_free(drawing *dr, blitter *bl) |
222 | { | 252 | { |
223 | dr->api->blitter_free(dr->handle, bl); | 253 | drawing_internal *dri = PRIVATE_CAST(dr); |
254 | dri->pub.api->blitter_free(dr, bl); | ||
224 | } | 255 | } |
225 | 256 | ||
226 | void blitter_save(drawing *dr, blitter *bl, int x, int y) | 257 | void blitter_save(drawing *dr, blitter *bl, int x, int y) |
227 | { | 258 | { |
228 | dr->api->blitter_save(dr->handle, bl, x, y); | 259 | drawing_internal *dri = PRIVATE_CAST(dr); |
260 | dri->pub.api->blitter_save(dr, bl, x, y); | ||
229 | } | 261 | } |
230 | 262 | ||
231 | void blitter_load(drawing *dr, blitter *bl, int x, int y) | 263 | void blitter_load(drawing *dr, blitter *bl, int x, int y) |
232 | { | 264 | { |
233 | dr->api->blitter_load(dr->handle, bl, x, y); | 265 | drawing_internal *dri = PRIVATE_CAST(dr); |
266 | dri->pub.api->blitter_load(dr, bl, x, y); | ||
234 | } | 267 | } |
235 | 268 | ||
236 | void print_begin_doc(drawing *dr, int pages) | 269 | void print_begin_doc(drawing *dr, int pages) |
237 | { | 270 | { |
238 | dr->api->begin_doc(dr->handle, pages); | 271 | drawing_internal *dri = PRIVATE_CAST(dr); |
272 | dri->pub.api->begin_doc(dr, pages); | ||
239 | } | 273 | } |
240 | 274 | ||
241 | void print_begin_page(drawing *dr, int number) | 275 | void print_begin_page(drawing *dr, int number) |
242 | { | 276 | { |
243 | dr->api->begin_page(dr->handle, number); | 277 | drawing_internal *dri = PRIVATE_CAST(dr); |
278 | dri->pub.api->begin_page(dr, number); | ||
244 | } | 279 | } |
245 | 280 | ||
246 | void print_begin_puzzle(drawing *dr, float xm, float xc, | 281 | void print_begin_puzzle(drawing *dr, float xm, float xc, |
247 | float ym, float yc, int pw, int ph, float wmm, | 282 | float ym, float yc, int pw, int ph, float wmm, |
248 | float scale) | 283 | float scale) |
249 | { | 284 | { |
250 | dr->scale = scale; | 285 | drawing_internal *dri = PRIVATE_CAST(dr); |
251 | dr->ncolours = 0; | 286 | dri->scale = scale; |
252 | dr->api->begin_puzzle(dr->handle, xm, xc, ym, yc, pw, ph, wmm); | 287 | dri->ncolours = 0; |
288 | dri->pub.api->begin_puzzle(dr, xm, xc, ym, yc, pw, ph, wmm); | ||
253 | } | 289 | } |
254 | 290 | ||
255 | void print_end_puzzle(drawing *dr) | 291 | void print_end_puzzle(drawing *dr) |
256 | { | 292 | { |
257 | dr->api->end_puzzle(dr->handle); | 293 | drawing_internal *dri = PRIVATE_CAST(dr); |
258 | dr->scale = 1.0F; | 294 | dri->pub.api->end_puzzle(dr); |
295 | dri->scale = 1.0F; | ||
259 | } | 296 | } |
260 | 297 | ||
261 | void print_end_page(drawing *dr, int number) | 298 | void print_end_page(drawing *dr, int number) |
262 | { | 299 | { |
263 | dr->api->end_page(dr->handle, number); | 300 | drawing_internal *dri = PRIVATE_CAST(dr); |
301 | dri->pub.api->end_page(dr, number); | ||
264 | } | 302 | } |
265 | 303 | ||
266 | void print_end_doc(drawing *dr) | 304 | void print_end_doc(drawing *dr) |
267 | { | 305 | { |
268 | dr->api->end_doc(dr->handle); | 306 | drawing_internal *dri = PRIVATE_CAST(dr); |
307 | dri->pub.api->end_doc(dr); | ||
269 | } | 308 | } |
270 | 309 | ||
271 | void print_get_colour(drawing *dr, int colour, bool printing_in_colour, | 310 | void print_get_colour(drawing *dr, int colour, bool printing_in_colour, |
272 | int *hatch, float *r, float *g, float *b) | 311 | int *hatch, float *r, float *g, float *b) |
273 | { | 312 | { |
274 | assert(colour >= 0 && colour < dr->ncolours); | 313 | drawing_internal *dri = PRIVATE_CAST(dr); |
275 | if (dr->colours[colour].hatch_when == 2 || | 314 | assert(colour >= 0 && colour < dri->ncolours); |
276 | (dr->colours[colour].hatch_when == 1 && !printing_in_colour)) { | 315 | if (dri->colours[colour].hatch_when == 2 || |
277 | *hatch = dr->colours[colour].hatch; | 316 | (dri->colours[colour].hatch_when == 1 && !printing_in_colour)) { |
317 | *hatch = dri->colours[colour].hatch; | ||
278 | } else { | 318 | } else { |
279 | *hatch = -1; | 319 | *hatch = -1; |
280 | if (printing_in_colour) { | 320 | if (printing_in_colour) { |
281 | *r = dr->colours[colour].r; | 321 | *r = dri->colours[colour].r; |
282 | *g = dr->colours[colour].g; | 322 | *g = dri->colours[colour].g; |
283 | *b = dr->colours[colour].b; | 323 | *b = dri->colours[colour].b; |
284 | } else { | 324 | } else { |
285 | *r = *g = *b = dr->colours[colour].grey; | 325 | *r = *g = *b = dri->colours[colour].grey; |
286 | } | 326 | } |
287 | } | 327 | } |
288 | } | 328 | } |
@@ -290,18 +330,19 @@ void print_get_colour(drawing *dr, int colour, bool printing_in_colour, | |||
290 | static int print_generic_colour(drawing *dr, float r, float g, float b, | 330 | static int print_generic_colour(drawing *dr, float r, float g, float b, |
291 | float grey, int hatch, int hatch_when) | 331 | float grey, int hatch, int hatch_when) |
292 | { | 332 | { |
293 | if (dr->ncolours >= dr->coloursize) { | 333 | drawing_internal *dri = PRIVATE_CAST(dr); |
294 | dr->coloursize = dr->ncolours + 16; | 334 | if (dri->ncolours >= dri->coloursize) { |
295 | dr->colours = sresize(dr->colours, dr->coloursize, | 335 | dri->coloursize = dri->ncolours + 16; |
336 | dri->colours = sresize(dri->colours, dri->coloursize, | ||
296 | struct print_colour); | 337 | struct print_colour); |
297 | } | 338 | } |
298 | dr->colours[dr->ncolours].hatch = hatch; | 339 | dri->colours[dri->ncolours].hatch = hatch; |
299 | dr->colours[dr->ncolours].hatch_when = hatch_when; | 340 | dri->colours[dri->ncolours].hatch_when = hatch_when; |
300 | dr->colours[dr->ncolours].r = r; | 341 | dri->colours[dri->ncolours].r = r; |
301 | dr->colours[dr->ncolours].g = g; | 342 | dri->colours[dri->ncolours].g = g; |
302 | dr->colours[dr->ncolours].b = b; | 343 | dri->colours[dri->ncolours].b = b; |
303 | dr->colours[dr->ncolours].grey = grey; | 344 | dri->colours[dri->ncolours].grey = grey; |
304 | return dr->ncolours++; | 345 | return dri->ncolours++; |
305 | } | 346 | } |
306 | 347 | ||
307 | int print_mono_colour(drawing *dr, int grey) | 348 | int print_mono_colour(drawing *dr, int grey) |
@@ -336,6 +377,8 @@ int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch) | |||
336 | 377 | ||
337 | void print_line_width(drawing *dr, int width) | 378 | void print_line_width(drawing *dr, int width) |
338 | { | 379 | { |
380 | drawing_internal *dri = PRIVATE_CAST(dr); | ||
381 | |||
339 | /* | 382 | /* |
340 | * I don't think it's entirely sensible to have line widths be | 383 | * I don't think it's entirely sensible to have line widths be |
341 | * entirely relative to the puzzle size; there is a point | 384 | * entirely relative to the puzzle size; there is a point |
@@ -348,10 +391,11 @@ void print_line_width(drawing *dr, int width) | |||
348 | * _square root_ of the main puzzle scale. Double the puzzle | 391 | * _square root_ of the main puzzle scale. Double the puzzle |
349 | * size, and the line width multiplies by 1.4. | 392 | * size, and the line width multiplies by 1.4. |
350 | */ | 393 | */ |
351 | dr->api->line_width(dr->handle, (float)sqrt(dr->scale) * width); | 394 | dri->pub.api->line_width(dr, (float)sqrt(dri->scale) * width); |
352 | } | 395 | } |
353 | 396 | ||
354 | void print_line_dotted(drawing *dr, bool dotted) | 397 | void print_line_dotted(drawing *dr, bool dotted) |
355 | { | 398 | { |
356 | dr->api->line_dotted(dr->handle, dotted); | 399 | drawing_internal *dri = PRIVATE_CAST(dr); |
400 | dri->pub.api->line_dotted(dr, dotted); | ||
357 | } | 401 | } |