X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=drawing.c;h=7f4a6cf6746eabdea9fba7a63f6d9b9900ef35d0;hb=3ce69e84cad15844282d691fa03e711c5353c05e;hp=63e27a4f04d0410dd47c7a39d4159f39248b2b77;hpb=af59dcf6858264103bbc621761feee3aed5aaf2a;p=sgt-puzzles.git diff --git a/drawing.c b/drawing.c index 63e27a4..7f4a6cf 100644 --- a/drawing.c +++ b/drawing.c @@ -7,15 +7,25 @@ * unchanged. However, on the printing side it tracks print colours * so the front end API doesn't have to. * - * FIXME: could we also sort out rewrite_statusbar in here? Also - * I'd _like_ to do automatic draw_updates, but it's a pain for - * draw_text in particular - I could invent a front end API which - * retrieved the text bounds and then do the alignment myself as - * well, except that that doesn't work for PS. As usual. + * FIXME: + * + * - I'd _like_ to do automatic draw_updates, but it's a pain for + * draw_text in particular. I'd have to invent a front end API + * which retrieved the text bounds. + * + that might allow me to do the alignment centrally as well? + * * perhaps not, because PS can't return this information, + * so there would have to be a special case for it. + * + however, that at least doesn't stand in the way of using + * the text bounds for draw_update, because PS doesn't need + * draw_update since it's printing-only. Any _interactive_ + * drawing API couldn't get away with refusing to tell you + * what parts of the screen a text draw had covered, because + * you would inevitably need to erase it later on. */ #include #include +#include #include #include @@ -23,7 +33,9 @@ struct print_colour { int hatch; + int hatch_when; /* 0=never 1=only-in-b&w 2=always */ float r, g, b; + float grey; }; struct drawing { @@ -32,9 +44,13 @@ struct drawing { struct print_colour *colours; int ncolours, coloursize; float scale; + /* `me' is only used in status_bar(), so print-oriented instances of + * this may set it to NULL. */ + midend *me; + char *laststatus; }; -drawing *drawing_init(const drawing_api *api, void *handle) +drawing *drawing_new(const drawing_api *api, midend *me, void *handle) { drawing *dr = snew(drawing); dr->api = api; @@ -42,11 +58,14 @@ drawing *drawing_init(const drawing_api *api, void *handle) dr->colours = NULL; dr->ncolours = dr->coloursize = 0; dr->scale = 1.0F; + dr->me = me; + dr->laststatus = NULL; return dr; } void drawing_free(drawing *dr) { + sfree(dr->laststatus); sfree(dr->colours); sfree(dr); } @@ -68,6 +87,34 @@ void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour); } +void draw_thick_line(drawing *dr, float thickness, + float x1, float y1, float x2, float y2, int colour) +{ + if (dr->api->draw_thick_line) { + dr->api->draw_thick_line(dr->handle, thickness, + x1, y1, x2, y2, colour); + } else { + /* We'll fake it up with a filled polygon. The tweak to the + * thickness empirically compensates for rounding errors, because + * polygon rendering uses integer coordinates. + */ + float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); + float tvhatx = (x2 - x1)/len * (thickness/2 - 0.2); + float tvhaty = (y2 - y1)/len * (thickness/2 - 0.2); + int p[8]; + + p[0] = x1 - tvhaty; + p[1] = y1 + tvhatx; + p[2] = x2 - tvhaty; + p[3] = y2 + tvhatx; + p[4] = x2 + tvhaty; + p[5] = y2 - tvhatx; + p[6] = x1 + tvhaty; + p[7] = y1 - tvhatx; + dr->api->draw_polygon(dr->handle, p, 4, colour, colour); + } +} + void draw_polygon(drawing *dr, int *coords, int npoints, int fillcolour, int outlinecolour) { @@ -108,10 +155,56 @@ void end_draw(drawing *dr) dr->api->end_draw(dr->handle); } +char *text_fallback(drawing *dr, const char *const *strings, int nstrings) +{ + int i; + + /* + * If the drawing implementation provides one of these, use it. + */ + if (dr && dr->api->text_fallback) + return dr->api->text_fallback(dr->handle, strings, nstrings); + + /* + * Otherwise, do the simple thing and just pick the first string + * that fits in plain ASCII. It will then need no translation + * out of UTF-8. + */ + for (i = 0; i < nstrings; i++) { + const char *p; + + for (p = strings[i]; *p; p++) + if (*p & 0x80) + break; + if (!*p) + return dupstr(strings[i]); + } + + /* + * The caller was responsible for making sure _some_ string in + * the list was in plain ASCII. + */ + assert(!"Should never get here"); + return NULL; /* placate optimiser */ +} + void status_bar(drawing *dr, char *text) { - if (dr->api->status_bar) - dr->api->status_bar(dr->handle, text); + char *rewritten; + + if (!dr->api->status_bar) + return; + + assert(dr->me); + + rewritten = midend_rewrite_statusbar(dr->me, text); + if (!dr->laststatus || strcmp(rewritten, dr->laststatus)) { + dr->api->status_bar(dr->handle, rewritten); + sfree(dr->laststatus); + dr->laststatus = rewritten; + } else { + sfree(rewritten); + } } blitter *blitter_new(drawing *dr, int w, int h) @@ -169,17 +262,27 @@ void print_end_doc(drawing *dr) dr->api->end_doc(dr->handle); } -void print_get_colour(drawing *dr, int colour, int *hatch, - float *r, float *g, float *b) +void print_get_colour(drawing *dr, int colour, int printing_in_colour, + int *hatch, float *r, float *g, float *b) { assert(colour >= 0 && colour < dr->ncolours); - *hatch = dr->colours[colour].hatch; - *r = dr->colours[colour].r; - *g = dr->colours[colour].g; - *b = dr->colours[colour].b; + if (dr->colours[colour].hatch_when == 2 || + (dr->colours[colour].hatch_when == 1 && !printing_in_colour)) { + *hatch = dr->colours[colour].hatch; + } else { + *hatch = -1; + if (printing_in_colour) { + *r = dr->colours[colour].r; + *g = dr->colours[colour].g; + *b = dr->colours[colour].b; + } else { + *r = *g = *b = dr->colours[colour].grey; + } + } } -int print_rgb_colour(drawing *dr, int hatch, float r, float g, float b) +static int print_generic_colour(drawing *dr, float r, float g, float b, + float grey, int hatch, int hatch_when) { if (dr->ncolours >= dr->coloursize) { dr->coloursize = dr->ncolours + 16; @@ -187,21 +290,42 @@ int print_rgb_colour(drawing *dr, int hatch, float r, float g, float b) struct print_colour); } dr->colours[dr->ncolours].hatch = hatch; + dr->colours[dr->ncolours].hatch_when = hatch_when; dr->colours[dr->ncolours].r = r; dr->colours[dr->ncolours].g = g; dr->colours[dr->ncolours].b = b; + dr->colours[dr->ncolours].grey = grey; return dr->ncolours++; } -int print_grey_colour(drawing *dr, int hatch, float grey) +int print_mono_colour(drawing *dr, int grey) { - return print_rgb_colour(dr, hatch, grey, grey, grey); + return print_generic_colour(dr, grey, grey, grey, grey, -1, 0); } -int print_mono_colour(drawing *dr, int grey) +int print_grey_colour(drawing *dr, float grey) +{ + return print_generic_colour(dr, grey, grey, grey, grey, -1, 0); +} + +int print_hatched_colour(drawing *dr, int hatch) +{ + return print_generic_colour(dr, 0, 0, 0, 0, hatch, 2); +} + +int print_rgb_mono_colour(drawing *dr, float r, float g, float b, int grey) +{ + return print_generic_colour(dr, r, g, b, grey, -1, 0); +} + +int print_rgb_grey_colour(drawing *dr, float r, float g, float b, float grey) +{ + return print_generic_colour(dr, r, g, b, grey, -1, 0); +} + +int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch) { - return print_rgb_colour(dr, grey ? HATCH_CLEAR : HATCH_SOLID, - grey, grey, grey); + return print_generic_colour(dr, r, g, b, 0, hatch, 1); } void print_line_width(drawing *dr, int width) @@ -218,5 +342,10 @@ void print_line_width(drawing *dr, int width) * _square root_ of the main puzzle scale. Double the puzzle * size, and the line width multiplies by 1.4. */ - dr->api->line_width(dr->handle, sqrt(dr->scale) * width); + dr->api->line_width(dr->handle, (float)sqrt(dr->scale) * width); +} + +void print_line_dotted(drawing *dr, int dotted) +{ + dr->api->line_dotted(dr->handle, dotted); }