Tweak the semantics of dsf_merge() so that the canonical element of
[sgt/puzzles] / drawing.c
index 63e27a4..26df1ff 100644 (file)
--- 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 <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <assert.h>
 #include <math.h>
 
@@ -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);
 }
@@ -110,8 +129,21 @@ void end_draw(drawing *dr)
 
 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 +201,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 +229,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_rgb_colour(dr, grey ? HATCH_CLEAR : HATCH_SOLID,
-                           grey, grey, grey);
+    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_generic_colour(dr, r, g, b, 0, hatch, 1);
 }
 
 void print_line_width(drawing *dr, int width)
@@ -218,5 +281,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);
 }