+ ui->drag_button = button;
+ ui->dsx = ui->dex = x;
+ ui->dsy = ui->dey = y;
+ ui->drag_ok = TRUE;
+ ui->cdisp = 0;
+ return ""; /* ui updated */
+ }
+
+ if ((IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) &&
+ ui->drag_button > 0) {
+ int xmin, ymin, xmax, ymax;
+ char *buf, *sep;
+ int buflen, bufsize, tmplen;
+
+ x = FROMCOORD(x);
+ y = FROMCOORD(y);
+ if (x < 0 || y < 0 || x >= w || y >= h) {
+ ui->drag_ok = FALSE;
+ } else {
+ /*
+ * Drags are limited to one row or column. Hence, we
+ * work out which coordinate is closer to the drag
+ * start, and move it _to_ the drag start.
+ */
+ if (abs(x - ui->dsx) < abs(y - ui->dsy))
+ x = ui->dsx;
+ else
+ y = ui->dsy;
+
+ ui->dex = x;
+ ui->dey = y;
+
+ ui->drag_ok = TRUE;
+ }
+
+ if (IS_MOUSE_DRAG(button))
+ return ""; /* ui updated */
+
+ /*
+ * The drag has been released. Enact it.
+ */
+ if (!ui->drag_ok) {
+ ui->drag_button = -1;
+ return ""; /* drag was just cancelled */
+ }
+
+ xmin = min(ui->dsx, ui->dex);
+ xmax = max(ui->dsx, ui->dex);
+ ymin = min(ui->dsy, ui->dey);
+ ymax = max(ui->dsy, ui->dey);
+ assert(0 <= xmin && xmin <= xmax && xmax < w);
+ assert(0 <= ymin && ymin <= ymax && ymax < h);
+
+ buflen = 0;
+ bufsize = 256;
+ buf = snewn(bufsize, char);
+ sep = "";
+ for (y = ymin; y <= ymax; y++)
+ for (x = xmin; x <= xmax; x++) {
+ int v = drag_xform(ui, x, y, state->grid[y*w+x]);
+ if (state->grid[y*w+x] != v) {
+ tmplen = sprintf(tmpbuf, "%s%c%d,%d", sep,
+ (int)(v == BLANK ? 'B' :
+ v == TENT ? 'T' : 'N'),
+ x, y);
+ sep = ";";
+
+ if (buflen + tmplen >= bufsize) {
+ bufsize = buflen + tmplen + 256;
+ buf = sresize(buf, bufsize, char);
+ }
+
+ strcpy(buf+buflen, tmpbuf);
+ buflen += tmplen;
+ }
+ }
+
+ ui->drag_button = -1; /* drag is terminated */