within the back end redraw function, so this is as good a place as
any to document it.)
+The supplied text is filtered through the mid-end for optional
+rewriting before being passed on to the front end; the mid-end will
+prepend the current game time if the game is timed (and may in
+future perform other rewriting if it seems like a good idea).
+
This function is for drawing only; it must never be called during
printing.
a more useful type. Thus, a drawing \e{object} (\c{drawing *)}
suitable for passing to the back end redraw or printing functions
is constructed by passing a \c{drawing_api} and a \cq{void *} to the
-function \cw{drawing_init()} (see \k{drawing-init}).
+function \cw{drawing_new()} (see \k{drawing-new}).
\S{drawingapi-draw-text} \cw{draw_text()}
This function behaves exactly like the back end \cw{status_bar()}
function; see \k{drawing-status-bar}.
-Front ends implementing this function should not use the provided
-text directly; they should call \cw{midend_rewrite_statusbar()}
-(\k{midend-rewrite-statusbar}) to process it first.
-
-In a game which has a timer, this function is likely to be called
-every time the timer goes off, i.e. many times a second. It is
-therefore likely to be common that this function is called with
-precisely the same text as the last time it was called. Front ends
-may well wish to detect this common case and avoid bothering to do
-anything. If they do, however, they \e{must} perform this check on
-the value \e{returned} from \cw{midend_rewrite_statusbar()}, rather
-than the value passed in to it (because the mid-end will frequently
-update the status-bar timer without the back end's intervention).
+Front ends implementing this function need not worry about it being
+called repeatedly with the same text; the middleware code in
+\cw{status_bar()} will take care of this.
Implementations of this API which do not provide drawing services
may define this function pointer to be \cw{NULL}; it will never be
which the front end needs to \e{call}, rather than helping to
implement. They are described in this section.
-\S{drawing-init} \cw{drawing_init()}
+\S{drawing-new} \cw{drawing_new()}
-\c drawing *drawing_init(const drawing_api *api, void *handle);
+\c drawing *drawing_new(const drawing_api *api, midend *me,
+\c void *handle);
This function creates a drawing object. It is passed a
\c{drawing_api}, which is a structure containing nothing but
function pointers; and also a \cq{void *} handle. The handle is
passed back to each function pointer when it is called.
+The \c{midend} parameter is used for rewriting the status bar
+contents: \cw{status_bar()} (see \k{drawing-status-bar}) has to call
+a function in the mid-end which might rewrite the status bar text.
+If the drawing object is to be used only for printing, or if the
+game is known not to call \cw{status_bar()}, this parameter may be
+\cw{NULL}.
+
\S{drawing-free} \cw{drawing_free()}
\c void drawing_free(drawing *dr);
function \cw{colours()} (\k{backend-colours}).
The parameters \c{drapi} and \c{drhandle} are passed to
-\cw{drawing_init()} (\k{drawing-init}) to construct a drawing object
+\cw{drawing_new()} (\k{drawing-new}) to construct a drawing object
which will be passed to the back end function \cw{redraw()}
(\k{backend-redraw}). Hence, all drawing-related function pointers
defined in \c{drapi} can expect to be called with \c{drhandle} as
\cw{activate_timer()} to be called from within a call to this
function.
-\H{midend-rewrite-statusbar} \cw{midend_rewrite_statusbar()}
-
-\c char *midend_rewrite_statusbar(midend *me, char *text);
-
-The front end should call this function from within
-\cw{status_bar()} (\k{drawing-status-bar}). It should be passed the
-string that was passed by the back end to \cw{status_bar()}; it will
-return a dynamically allocated string adjusted by the mid-end.
-(Specifically, adjusted to include the timer if the game is a timed
-one.) The returned value should be placed in the actual status bar
-in place of the input value.
-
-(This is a nasty piece of architecture; I apologise for it. It would
-seem a lot more pleasant to have the back end pass its status bar
-text to the mid-end, which in turn would rewrite it and pass it on
-to the front end, so that each front end needed to do nothing
-strange. The main reason why I haven't done this is because it means
-the back end redraw function would need to be passed a mid-end
-pointer \e{as well} as a front end pointer, which seemed like an
-excessive proliferation of opaque handles. The only way to avoid
-that proliferation would be to have all the drawing API functions
-also gatewayed through the mid-end, and that seemed like an
-excessive proliferation of wrapper functions. The current setup
-isn't nice, but it has minimal impact and I'm unconvinced that any
-of the other options are an improvement.)
-
\H{midend-serialise} \cw{midend_serialise()}
\c void midend_serialise(midend *me,
* 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>
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;
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);
}
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)
GtkWidget *cfgbox;
void *paste_data;
int paste_data_len;
- char *laststatus;
int pw, ph; /* pixmap size (w, h are area size) */
int ox, oy; /* offset of pixmap in drawing area */
char *filesel_name;
void gtk_status_bar(void *handle, char *text)
{
frontend *fe = (frontend *)handle;
- char *rewritten;
assert(fe->statusbar);
- rewritten = midend_rewrite_statusbar(fe->me, text);
- if (!fe->laststatus || strcmp(rewritten, fe->laststatus)) {
- gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx);
- gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, rewritten);
- sfree(fe->laststatus);
- fe->laststatus = rewritten;
- } else {
- sfree(rewritten);
- }
+ gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx);
+ gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, text);
}
void gtk_start_draw(void *handle)
fe->fonts = NULL;
fe->nfonts = fe->fontsize = 0;
- fe->laststatus = NULL;
-
fe->paste_data = NULL;
fe->paste_data_len = 0;
me->elapsed = 0.0F;
me->tilesize = me->winwidth = me->winheight = 0;
if (drapi)
- me->drawing = drawing_init(drapi, drhandle);
+ me->drawing = drawing_new(drapi, me, drhandle);
else
me->drawing = NULL;
ps->ytop = 0;
ps->clipped = FALSE;
ps->hatchthick = ps->hatchspace = ps->gamewidth = ps->gameheight = 0;
- ps->drawing = drawing_init(&ps_drawing, ps);
+ ps->drawing = drawing_new(&ps_drawing, NULL, ps);
return ps;
}
/*
* drawing.c
*/
-drawing *drawing_init(const drawing_api *api, void *handle);
+drawing *drawing_new(const drawing_api *api, midend *me, void *handle);
void drawing_free(drawing *dr);
void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
int align, int colour, char *text);
HPEN oldpen;
char *help_path;
int help_has_contents;
- char *laststatus;
enum { DRAWING, PRINTING, NOTHING } drawstatus;
DOCINFO di;
int printcount, printw, printh, printsolns, printcurr, printcolour;
static void win_status_bar(void *handle, char *text)
{
frontend *fe = (frontend *)handle;
- char *rewritten;
- rewritten = midend_rewrite_statusbar(fe->me, text);
- if (!fe->laststatus || strcmp(rewritten, fe->laststatus)) {
- SetWindowText(fe->statusbar, rewritten);
- sfree(fe->laststatus);
- fe->laststatus = rewritten;
- } else {
- sfree(rewritten);
- }
+ SetWindowText(fe->statusbar, text);
}
static blitter *win_blitter_new(void *handle, int w, int h)
fe->drawstatus = PRINTING;
fe->hdc = pd.hDC;
- fe->dr = drawing_init(&win_drawing, fe);
+ fe->dr = drawing_new(&win_drawing, NULL, fe);
document_print(doc, fe->dr);
drawing_free(fe->dr);
fe->dr = NULL;
fe->fonts = NULL;
fe->nfonts = fe->fontsize = 0;
- fe->laststatus = NULL;
-
{
int i, ncolours;
float *colours;