Stop the analysis pass in Loopy's redraw routine from being
[sgt/puzzles] / drawing.c
index 4204c4c..7f4a6cf 100644 (file)
--- a/drawing.c
+++ b/drawing.c
@@ -33,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 {
@@ -85,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)
 {
@@ -125,6 +155,39 @@ 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)
 {
     char *rewritten;
@@ -199,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;
@@ -217,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_rgb_colour(dr, grey ? HATCH_CLEAR : HATCH_SOLID,
-                           grey, grey, 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_generic_colour(dr, r, g, b, 0, hatch, 1);
 }
 
 void print_line_width(drawing *dr, int width)
@@ -248,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);
 }