~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to terps/nitfol/io.c

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  Nitfol - z-machine interpreter using Glk for output.
 
2
    Copyright (C) 1999  Evin Robertson
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program; if not, write to the Free Software
 
16
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 
17
 
 
18
    The author can be reached at nitfol@deja.com
 
19
*/
 
20
#include "nitfol.h"
 
21
#include "nio.h"
 
22
 
 
23
#ifdef HEADER
 
24
 
 
25
typedef struct z_window *zwinid;
 
26
 
 
27
#endif
 
28
 
 
29
BOOL is_fixed;       /* If we are forcing output to be fixed-width */
 
30
 
 
31
 
 
32
/* descriptions of z-machine colors, in glk 0x00rrggbb style.
 
33
   -1 means to call glk_stylehint_clear instead of glk_stylehint_set.
 
34
   The 'current color' will be overwritten on calls to set_colour.
 
35
 
 
36
   Go ahead and customize these (making background colors lighter than
 
37
   foreground colors might be interesting)
 
38
*/
 
39
 
 
40
glsi32 bgcolortable[] = {
 
41
  -1L,          /* current color */
 
42
  -1L,          /* defualt setting */
 
43
  0x00000000L,  /* black */
 
44
  0x00ff0000L,  /* red */
 
45
  0x00008000L,  /* green */
 
46
  0x00ffff00L,  /* yellow */
 
47
  0x000000ffL,  /* blue */
 
48
  0x00ff00ffL,  /* magenta */
 
49
  0x0000ffffL,  /* cyan */
 
50
  0x00ffffffL,  /* white */
 
51
  0x00c0c0c0L,  /* light grey */
 
52
  0x00808080L,  /* medium grey */
 
53
  0x00404040L   /* dark grey */
 
54
};
 
55
 
 
56
glsi32 fgcolortable[] = {
 
57
  -1L,          /* current color */
 
58
  -1L,          /* defualt setting */
 
59
  0x00000000L,  /* black */
 
60
  0x00ff0000L,  /* red */
 
61
  0x00008000L,  /* green */
 
62
  0x00ffff00L,  /* yellow */
 
63
  0x000000ffL,  /* blue */
 
64
  0x00ff00ffL,  /* magenta */
 
65
  0x0000ffffL,  /* cyan */
 
66
  0x00ffffffL,  /* white */
 
67
  0x00c0c0c0L,  /* light grey */
 
68
  0x00808080L,  /* medium grey */
 
69
  0x00404040L   /* dark grey */
 
70
};
 
71
 
 
72
 
 
73
static void killglkwithcolor(glui32 styl, int fore, int back)
 
74
{
 
75
  if(fgcolortable[fore] == -1)
 
76
    glk_stylehint_clear(wintype_AllTypes, styl,
 
77
                        stylehint_TextColor);
 
78
  else
 
79
    glk_stylehint_set(wintype_AllTypes, styl,
 
80
                      stylehint_TextColor, fgcolortable[fore]);
 
81
 
 
82
  if(bgcolortable[back] == -1)
 
83
    glk_stylehint_clear(wintype_AllTypes, styl,
 
84
                        stylehint_BackColor);
 
85
  else
 
86
    glk_stylehint_set(wintype_AllTypes, styl,
 
87
                      stylehint_BackColor, bgcolortable[back]);
 
88
}
 
89
 
 
90
 
 
91
static void set_stylehints(char fore, char back)
 
92
{
 
93
  glui32 n;
 
94
  for(n = 0; n < style_NUMSTYLES; n++)
 
95
    killglkwithcolor(n, fore, back);
 
96
 
 
97
  /* Subheader will be used for bold */
 
98
  glk_stylehint_set(wintype_TextBuffer, style_Subheader,
 
99
                    stylehint_Weight, 1);
 
100
 
 
101
  /* BlockQuote will be used for reverse proportional text */
 
102
  glk_stylehint_set(wintype_TextBuffer, style_BlockQuote,
 
103
                    stylehint_Proportional, 0);
 
104
  glk_stylehint_set(wintype_TextBuffer, style_BlockQuote,
 
105
                    stylehint_Justification, stylehint_just_Centered);
 
106
#ifdef stylehint_ReverseColor
 
107
  glk_stylehint_set(wintype_TextBuffer, style_BlockQuote,
 
108
                    stylehint_ReverseColor, 1);
 
109
#endif
 
110
 
 
111
  /* User1 will be used for bold italics */
 
112
  glk_stylehint_set(wintype_TextBuffer, style_User1,
 
113
                    stylehint_Weight, 1);
 
114
  glk_stylehint_set(wintype_TextBuffer, style_User1,
 
115
                    stylehint_Oblique, 1);
 
116
 
 
117
  /* User2 will be used for proportional bold/italic */
 
118
  glk_stylehint_set(wintype_TextBuffer, style_User2,
 
119
                    stylehint_Proportional, 0);
 
120
  glk_stylehint_set(wintype_TextBuffer, style_User2,
 
121
                    stylehint_Weight, 1);
 
122
}
 
123
 
 
124
#define sBOLD 1
 
125
#define sITAL 2
 
126
#define sFIXE 4
 
127
#define sREVE 8
 
128
 
 
129
#if 0
 
130
 
 
131
static glui32 bitmap_to_style[16] = {
 
132
  style_Normal,
 
133
  style_Subheader,   /* sBOLD */
 
134
  style_Emphasized,  /* sITAL */
 
135
  style_User1,       /* sBOLD | sITAL */
 
136
  style_Preformatted,/* sFIXE */
 
137
  style_User2,       /* sFIXE | sBOLD */
 
138
  style_User2,       /* sFIXE | sITAL */
 
139
  style_User2,       /* sFIXE | sBOLD | sITAL*/
 
140
  style_BlockQuote,  /* sREVE */
 
141
  style_BlockQuote,  /* sREVE | sBOLD */
 
142
  style_BlockQuote,  /* sREVE | sITAL */
 
143
  style_BlockQuote,  /* sREVE | sBOLD | sITAL */
 
144
  style_BlockQuote,  /* sFIXE | sREVE */
 
145
  style_BlockQuote,  /* sFIXE | sREVE | sBOLD */
 
146
  style_BlockQuote,  /* sFIXE | sREVE | sITAL */
 
147
  style_BlockQuote   /* sFIXE | sREVE | sBOLD | sITAL */
 
148
};
 
149
 
 
150
#else
 
151
 
 
152
static glui32 bitmap_to_style[16] = {
 
153
  style_Normal,
 
154
  style_Subheader,   /* sBOLD */
 
155
  style_Emphasized,  /* sITAL */
 
156
  style_Subheader,   /* sBOLD | sITAL */
 
157
  style_Preformatted,/* sFIXE */
 
158
  style_Subheader,   /* sFIXE | sBOLD */
 
159
  style_Emphasized,  /* sFIXE | sITAL */
 
160
  style_Subheader,   /* sFIXE | sBOLD | sITAL*/
 
161
  style_Normal,
 
162
  style_Subheader,   /* sBOLD */
 
163
  style_Emphasized,  /* sITAL */
 
164
  style_Subheader,   /* sBOLD | sITAL */
 
165
  style_Preformatted,/* sFIXE */
 
166
  style_Subheader,   /* sFIXE | sBOLD */
 
167
  style_Emphasized,  /* sFIXE | sITAL */
 
168
  style_Subheader    /* sFIXE | sBOLD | sITAL*/
 
169
};
 
170
 
 
171
#endif
 
172
 
 
173
typedef struct {
 
174
  char fore;
 
175
  char back;
 
176
  unsigned char style;
 
177
} colorstyle;
 
178
 
 
179
typedef struct {
 
180
  glui32 image_num;
 
181
  glui32 x, y;
 
182
  glui32 width, height;
 
183
} z_image;
 
184
 
 
185
 
 
186
struct z_window {
 
187
  winid_t win;
 
188
  strid_t str;
 
189
  glui32 wintype;
 
190
  glui32 method;
 
191
 
 
192
  strid_t transcript;
 
193
 
 
194
  BOOL glk_input_pending;
 
195
  glui32 pending_input_type;
 
196
  glui32 pending_input_length;
 
197
 
 
198
  /* for upper window of v3 - returns # of lines drawn */
 
199
  glui32 (*draw_callback)(winid_t win, glui32 width, glui32 height);
 
200
  BOOL (*mouse_callback)(BOOL is_char_event, winid_t win, glui32 x, glui32 y);
 
201
  
 
202
  glui32 width, height;
 
203
  glui32 x1, y1, x2, y2;
 
204
 
 
205
  glui32 last_height;   /* What the height was last time we got input */
 
206
  glui32 biggest_height;/* The biggest it's been since */
 
207
 
 
208
  glui32 curr_offset;   /* offset into text_buffer/color_buffer */
 
209
  glui32 max_offset;    /* curr_offset must stay < max_offset */
 
210
  glui32 buffer_size;   /* max_offset must stay < buffer_size */
 
211
 
 
212
  BOOL dirty;           /* Has window been changed since last redraw? */
 
213
  BOOL defined;         /* Is our location well defined? */
 
214
 
 
215
  unsigned char *text_buffer;  /* whole window for grid, current line for buffer */
 
216
  colorstyle *color_buffer;
 
217
 
 
218
  z_image images[12];
 
219
 
 
220
  colorstyle current;
 
221
  colorstyle actual;
 
222
};
 
223
 
 
224
 
 
225
#define num_z_windows 16
 
226
 
 
227
static struct z_window game_windows[num_z_windows];
 
228
 
 
229
static glui32 upper_width, upper_height;
 
230
 
 
231
 
 
232
static int waitforinput(zwinid window, glui32 *val,
 
233
                        BOOL (*timer_callback)(zword), zword timer_arg);
 
234
 
 
235
 
 
236
void set_glk_stream_current(void)
 
237
{
 
238
  z_flush_text(&game_windows[0]);
 
239
  glk_stream_set_current(game_windows[0].str);
 
240
}
 
241
 
 
242
void draw_intext_picture(zwinid window, glui32 picture, glui32 alignment)
 
243
{
 
244
  z_flush_text(window);
 
245
  wrap_glk_image_draw(window->win, picture, alignment, 0);
 
246
}
 
247
 
 
248
void draw_picture(zwinid window, glui32 picture, glui32 x, glui32 y)
 
249
{
 
250
  int i;
 
251
  int useimage = -1;
 
252
  glui32 width, height;
 
253
 
 
254
  wrap_glk_image_get_info(operand[0], &width, &height);
 
255
 
 
256
  for(i = 0; i < 12; i++) {
 
257
    if(is_in_bounds(window->images[i].x, window->images[i].y,
 
258
                    window->images[i].width, window->images[i].height,
 
259
                    x, y, width, height))
 
260
      useimage = i;
 
261
  }
 
262
  if(useimage == -1)
 
263
    for(i = 0; i < 12; i++)
 
264
      if(window->images[i].image_num == 0)
 
265
        useimage = i;
 
266
  if(useimage == -1)
 
267
    return;
 
268
 
 
269
  window->images[useimage].image_num = picture;
 
270
  window->images[useimage].x = x;
 
271
  window->images[useimage].y = y;
 
272
  window->images[useimage].width = width;
 
273
  window->images[useimage].height = height;
 
274
}
 
275
 
 
276
 
 
277
static int showstuffcount = 0;
 
278
 
 
279
/* Show an interpreter message */
 
280
void showstuff(const char *title, const char *type, const char *message, offset number)
 
281
{
 
282
  static BOOL loopy = FALSE;
 
283
  if(loopy) {
 
284
    loopy = FALSE;
 
285
    n_show_fatal(E_SYSTEM, "loopy message reporting", 0);
 
286
  }
 
287
  loopy = TRUE;
 
288
 
 
289
  z_pause_timed_input(&game_windows[0]);
 
290
  z_flush_text(&game_windows[0]);
 
291
  glk_stream_set_current(game_windows[0].str);
 
292
 
 
293
  glk_set_style(style_Alert);
 
294
  w_glk_put_string("\n[");
 
295
  w_glk_put_string(title);
 
296
  w_glk_put_string(": ");
 
297
  w_glk_put_string(type);
 
298
  w_glk_put_string("]: ");
 
299
  w_glk_put_string(message);
 
300
  w_glk_put_string(" (");
 
301
  g_print_snumber(number);
 
302
  w_glk_put_string(") ");
 
303
 
 
304
#ifdef DEBUGGING
 
305
  infix_gprint_loc(stack_get_depth(), 0);
 
306
#else
 
307
  w_glk_put_string("PC=");
 
308
  g_print_number(oldPC);
 
309
  glk_put_char('\n');
 
310
#endif
 
311
 
 
312
  if(++showstuffcount == 100) {
 
313
    w_glk_put_string("[pausing every 100 errors]\n");
 
314
    z_wait_for_key(&game_windows[0]);
 
315
  }
 
316
 
 
317
  glk_set_style(style_Normal);
 
318
 
 
319
  loopy = FALSE;
 
320
}
 
321
 
 
322
 
 
323
void init_lower(zwinid *lower)
 
324
{
 
325
  zwinid lower_win = &game_windows[0];
 
326
  glui32 i;
 
327
 
 
328
  if(lower)
 
329
    *lower = lower_win;
 
330
 
 
331
  if(lower_win->win) {
 
332
    z_pause_timed_input(lower_win);
 
333
    glk_window_close(lower_win->win, NULL);
 
334
  }
 
335
 
 
336
  set_stylehints(lower_win->current.fore,
 
337
                 lower_win->current.back);
 
338
 
 
339
 
 
340
  lower_win->dirty = TRUE;
 
341
  lower_win->wintype = wintype_TextBuffer;
 
342
  lower_win->method = winmethod_Below;
 
343
  lower_win->curr_offset = 0;
 
344
  lower_win->max_offset = 80 * 24;
 
345
  lower_win->buffer_size = lower_win->max_offset;
 
346
 
 
347
  if(!lower_win->text_buffer)
 
348
    lower_win->text_buffer = (unsigned char *) n_malloc(lower_win->buffer_size);
 
349
  if(!lower_win->color_buffer)
 
350
    lower_win->color_buffer = (colorstyle *) n_malloc(lower_win->buffer_size * sizeof(colorstyle));
 
351
 
 
352
  for(i = 0; i < lower_win->buffer_size; i++) {
 
353
    lower_win->text_buffer[i] = ' ';
 
354
    lower_win->color_buffer[i] = lower_win->current;
 
355
  }
 
356
 
 
357
  lower_win->actual = lower_win->current;
 
358
 
 
359
  lower_win->win = glk_window_open(game_windows[1].win,
 
360
                                    winmethod_Below | winmethod_Proportional,
 
361
                                    50,  /* Percent doesn't matter */
 
362
                                    wintype_TextBuffer, 0);
 
363
 
 
364
 
 
365
  if(lower_win->win == 0) {
 
366
    n_show_fatal(E_OUTPUT, "cannot open lower window", 0);
 
367
    return;
 
368
  }
 
369
 
 
370
  lower_win->str = glk_window_get_stream(lower_win->win);
 
371
 
 
372
  if(lower_win->transcript)
 
373
    glk_window_set_echo_stream(lower_win->win, lower_win->transcript);
 
374
}
 
375
 
 
376
 
 
377
void init_upper(zwinid *upper)
 
378
{
 
379
  zwinid upper_win = &game_windows[1];
 
380
  glui32 i;
 
381
 
 
382
  if(upper)
 
383
    *upper = upper_win;
 
384
 
 
385
  if(upper_win->win) {
 
386
    z_pause_timed_input(upper_win);
 
387
    glk_window_close(upper_win->win, NULL);
 
388
  }
 
389
 
 
390
  upper_win->dirty = TRUE;
 
391
  upper_win->wintype = wintype_TextGrid;
 
392
  upper_win->method = winmethod_Above | winmethod_Fixed;
 
393
  upper_win->height = 0;
 
394
  upper_win->width = upper_width;
 
395
  upper_win->curr_offset = 0;
 
396
  upper_win->max_offset = upper_height * upper_width;
 
397
  upper_win->buffer_size = upper_win->max_offset;
 
398
 
 
399
  if(!upper_win->text_buffer)
 
400
    upper_win->text_buffer = (unsigned char *) n_malloc(upper_win->buffer_size);
 
401
  if(!upper_win->color_buffer)
 
402
    upper_win->color_buffer = (colorstyle *) n_malloc(upper_win->buffer_size * sizeof(colorstyle));
 
403
 
 
404
  for(i = 0; i < upper_win->buffer_size; i++) {
 
405
    upper_win->text_buffer[i] = ' ';
 
406
    upper_win->color_buffer[i] = upper_win->current;
 
407
  }
 
408
 
 
409
  upper_win->actual = upper_win->current;
 
410
 
 
411
  upper_win->win = glk_window_open(game_windows[0].win,
 
412
                                    winmethod_Above | winmethod_Fixed,
 
413
                                    1, /* XXX huh? upper_height, */
 
414
                                    wintype_TextGrid, 1);
 
415
 
 
416
  if(upper_win->win == 0) {
 
417
    upper_win->str = 0;
 
418
    return;
 
419
  }
 
420
 
 
421
  upper_win->str = glk_window_get_stream(upper_win->win);
 
422
 
 
423
  if(upper_win->str == 0) {
 
424
    glk_window_close(upper_win->win, NULL);
 
425
    upper_win->win = 0;
 
426
    return;
 
427
  }
 
428
}
 
429
 
 
430
 
 
431
void z_init_windows(BOOL dofixed,
 
432
                    glui32 (*draw_callback)(winid_t, glui32, glui32),
 
433
                    BOOL (*mouse_callback)(BOOL, winid_t, glui32, glui32),
 
434
                    glui32 maxwidth, glui32 maxheight,
 
435
                    zwinid *upper, zwinid *lower)
 
436
{
 
437
  colorstyle defaultstyle;
 
438
  defaultstyle.fore = 1; defaultstyle.back = 1; defaultstyle.style = 0;
 
439
 
 
440
  is_fixed = dofixed;
 
441
 
 
442
  kill_windows();
 
443
 
 
444
  upper_width = maxwidth; upper_height = maxheight;
 
445
 
 
446
  game_windows[0].current = game_windows[1].current = defaultstyle;
 
447
  game_windows[1].draw_callback  = draw_callback;
 
448
  game_windows[1].mouse_callback = mouse_callback;
 
449
 
 
450
  init_lower(lower);
 
451
  init_upper(upper);
 
452
}
 
453
 
 
454
 
 
455
zwinid z_split_screen(glui32 wintype, glui32 method,
 
456
                      glui32 (*draw_callback)(winid_t, glui32, glui32),
 
457
                      BOOL (*mouse_callback)(BOOL, winid_t, glui32, glui32))
 
458
{
 
459
  int i;
 
460
  for(i = 0; i < num_z_windows; i++) {
 
461
    if(!game_windows[i].win) {
 
462
      winid_t root = glk_window_get_root();
 
463
      game_windows[i].win = glk_window_open(root, method, 0, wintype, 0);
 
464
      game_windows[i].str = glk_window_get_stream(game_windows[i].win);
 
465
      game_windows[i].wintype = wintype;
 
466
      game_windows[i].method = method;
 
467
      game_windows[i].transcript = NULL;
 
468
      game_windows[i].glk_input_pending = FALSE;
 
469
      game_windows[i].draw_callback = draw_callback;
 
470
      game_windows[i].mouse_callback = mouse_callback;
 
471
      game_windows[i].width = 0;
 
472
      game_windows[i].height = 0;
 
473
      game_windows[i].curr_offset = 0;
 
474
      game_windows[i].max_offset = 1;
 
475
      game_windows[i].buffer_size = 2;
 
476
      game_windows[i].text_buffer = n_malloc(2);
 
477
      game_windows[i].color_buffer = n_malloc(2);
 
478
      game_windows[i].dirty = TRUE;
 
479
      return &game_windows[i];
 
480
    }
 
481
  }
 
482
  return NULL;
 
483
}
 
484
 
 
485
 
 
486
void z_kill_window(zwinid win)
 
487
{
 
488
  if(!win)
 
489
    return;
 
490
  n_free(win->text_buffer);
 
491
  win->text_buffer = NULL;
 
492
  n_free(win->color_buffer);
 
493
  win->color_buffer = NULL;
 
494
  win->transcript = NULL;
 
495
  glk_window_close(win->win, NULL);
 
496
  win->win = NULL;
 
497
  win->str = NULL;
 
498
}
 
499
 
 
500
 
 
501
/* close any open windows */
 
502
void kill_windows(void)
 
503
{
 
504
  int i;
 
505
 
 
506
  for(i = 0; i < num_z_windows; i++)
 
507
    z_clear_window(&game_windows[i]);
 
508
 
 
509
  free_windows();
 
510
  for(i = 0; i < num_z_windows; i++) {
 
511
    if(game_windows[i].win) {
 
512
      game_windows[i].transcript = NULL;
 
513
 
 
514
      glk_window_close(game_windows[i].win, NULL);
 
515
      game_windows[i].win = NULL;
 
516
      game_windows[i].str = NULL;
 
517
    }
 
518
  }
 
519
  showstuffcount = 0;
 
520
}
 
521
 
 
522
 
 
523
/* free memory space used by windows, but don't close them */
 
524
void free_windows(void)
 
525
{
 
526
  int i;
 
527
 
 
528
  z_flush_all_windows();
 
529
 
 
530
  for(i = 0; i < num_z_windows; i++) {
 
531
    if(game_windows[i].win) {
 
532
      n_free(game_windows[i].text_buffer);
 
533
      game_windows[i].text_buffer = NULL;
 
534
 
 
535
      n_free(game_windows[i].color_buffer);
 
536
      game_windows[i].color_buffer = NULL;
 
537
    }
 
538
  }
 
539
}
 
540
 
 
541
zwinid z_find_win(winid_t win)
 
542
{
 
543
  int i;
 
544
  for(i = 0; i < num_z_windows; i++) {
 
545
    if(game_windows[i].win == win)
 
546
      return &game_windows[i];
 
547
  }
 
548
  return NULL;
 
549
}
 
550
 
 
551
 
 
552
static BOOL coloreq(colorstyle a, colorstyle b) /* return true if colors are equivalent */
 
553
{
 
554
  return (fgcolortable[(int) a.fore] == fgcolortable[(int) b.fore]) &&
 
555
         (bgcolortable[(int) a.back] == bgcolortable[(int) b.back]);
 
556
}
 
557
 
 
558
 
 
559
static void checkforblockquote(zwinid window, zwinid dest_win)
 
560
{
 
561
  if(window->biggest_height > window->last_height &&
 
562
     window->biggest_height > window->height) {
 
563
    /* find borders of the blockquote */
 
564
    unsigned leftx = window->width, rightx = 0;
 
565
    unsigned topy = window->biggest_height;
 
566
    unsigned bottomy = window->height;
 
567
    unsigned x, y, i;
 
568
 
 
569
    i = window->height * window->width;
 
570
    for(y = window->height; y < window->biggest_height; y++)
 
571
      for(x = 0; x < window->width; x++)
 
572
        if(window->text_buffer[i++] != ' ') {
 
573
          if(x < leftx)
 
574
            leftx = x;
 
575
          if(x > rightx)
 
576
            rightx = x;
 
577
          if(y < topy)
 
578
            topy = y;
 
579
          if(y > bottomy)
 
580
            bottomy = y;
 
581
        }
 
582
    
 
583
    z_pause_timed_input(dest_win);
 
584
    glk_stream_set_current(game_windows[1].str);
 
585
    glk_put_char(10);
 
586
    glk_set_style(style_BlockQuote);
 
587
    
 
588
    /* draw the blockquote */
 
589
    for(y = topy; y <= bottomy; y++) {
 
590
      i = y * window->width + leftx;
 
591
      for(x = leftx; x <= rightx; x++)
 
592
        glk_put_char(window->text_buffer[i++]);
 
593
      glk_put_char(10);
 
594
    }
 
595
  }
 
596
}
 
597
 
 
598
 
 
599
void z_pause_timed_input(zwinid window)
 
600
{
 
601
  event_t eep;
 
602
  if(window->glk_input_pending) {
 
603
    window->glk_input_pending = FALSE;
 
604
 
 
605
    switch(window->pending_input_type) {
 
606
    case evtype_CharInput:
 
607
      glk_cancel_char_event(window->win);
 
608
      break;
 
609
    case evtype_LineInput:
 
610
      glk_cancel_line_event(window->win, &eep);
 
611
      window->pending_input_length = eep.val1;
 
612
    }
 
613
  }
 
614
}
 
615
 
 
616
 
 
617
void z_flush_all_windows(void)
 
618
{
 
619
  int window;
 
620
  for(window = 0; window < num_z_windows; window++) {
 
621
    if(game_windows[window].dirty) {
 
622
      z_pause_timed_input(&game_windows[window]);
 
623
      
 
624
      switch(game_windows[window].wintype) {
 
625
      case wintype_TextBuffer:
 
626
        z_flush_text(&game_windows[window]);
 
627
        break;
 
628
      case wintype_TextGrid:
 
629
        z_flush_fixed(&game_windows[window]);
 
630
        break;
 
631
      case wintype_Graphics:
 
632
        z_flush_graphics(&game_windows[window]);
 
633
        break;
 
634
      }
 
635
    }
 
636
  }
 
637
}
 
638
 
 
639
void z_draw_all_windows(void)
 
640
{
 
641
  int window;
 
642
  for(window = 0; window < num_z_windows; window++) {
 
643
    if(game_windows[window].wintype == wintype_TextGrid) {
 
644
      game_windows[window].dirty = TRUE;
 
645
      z_flush_fixed(&game_windows[window]);
 
646
    }
 
647
  }
 
648
}
 
649
 
 
650
 
 
651
static void z_put_styled_string(zwinid window, unsigned char *text,
 
652
                                colorstyle *color, glui32 length)
 
653
{
 
654
  glui32 n;
 
655
  colorstyle laststyle = color[0];
 
656
 
 
657
  if(!length)
 
658
    return;
 
659
 
 
660
  glk_set_style_stream(window->str, bitmap_to_style[laststyle.style]);
 
661
 
 
662
  for(n = 0; n < length; n++) {
 
663
    if(color[n].style != laststyle.style)
 
664
      glk_set_style_stream(window->str, bitmap_to_style[color[n].style]);
 
665
    glk_put_char_stream(window->str, text[n]);
 
666
    laststyle = color[n];
 
667
  }
 
668
}
 
669
 
 
670
void z_flush_fixed(zwinid window)
 
671
{
 
672
  glui32 winx, winy;
 
673
  winid_t o;
 
674
  glui32 start_line, end_line;
 
675
 
 
676
  /* If there's no such window, give up */
 
677
  if(!window->win || !window->str ||
 
678
     !window->text_buffer || !window->color_buffer)
 
679
    return;
 
680
 
 
681
  /* glk doesn't allow writing to a window while input is pending */
 
682
  z_pause_timed_input(window);
 
683
 
 
684
  end_line = window->height;
 
685
 
 
686
  /* Has the window grown and shrunk?  If so, probably because someone wants
 
687
     to draw a box quote - don't let them shrink the window quite so fast */
 
688
  if(window->biggest_height > window->last_height &&
 
689
     window->biggest_height > window->height)
 
690
    end_line = window->biggest_height;
 
691
 
 
692
  /* For v3 games, there's a callback function to draw the room name and
 
693
     score; if this is present, we start drawing at a lower position */
 
694
  start_line = 0;
 
695
  if(window->draw_callback)
 
696
    start_line = window->draw_callback(NULL, 0, 0);
 
697
  end_line += start_line;
 
698
 
 
699
  o = glk_window_get_parent(window->win);
 
700
#if 0
 
701
  glk_window_get_size(window->win, &winx, &winy);
 
702
  if (!(window->method & winmethod_Above || window->method & winmethod_Below)
 
703
      || winy != end_line)
 
704
    glk_window_set_arrangement(o, window->method,
 
705
                               end_line, window->win);
 
706
#else
 
707
  glk_window_set_arrangement(o, window->method, end_line, window->win);
 
708
#endif
 
709
  glk_window_get_size(window->win, &winx, &winy);
 
710
 
 
711
  if(window->draw_callback) {
 
712
    glk_stream_set_current(window->str);
 
713
    glk_window_clear(window->win);
 
714
    glk_window_move_cursor(window->win, 0, 0);
 
715
    window->draw_callback(window->win, winx, winy);
 
716
  }
 
717
 
 
718
  if(end_line > start_line && window->dirty) {
 
719
 
 
720
    unsigned padleft = 0, padmiddle = 0, padright = 0;
 
721
    unsigned skipleft = 0, skipmiddle = 0, skipright = 0;
 
722
    unsigned width;
 
723
    unsigned firstwidth, lastwidth;
 
724
 
 
725
    unsigned x, y, i;
 
726
 
 
727
    /* Calculate how much space is used for margins */
 
728
 
 
729
    unsigned left_margin = window->width, right_margin = window->width;
 
730
 
 
731
    i = 0;
 
732
    for(y = start_line; y < end_line; y++) {
 
733
      
 
734
      for(x = 0; x < window->width; x++)
 
735
        if(window->text_buffer[i + x] != ' ') {
 
736
          if(x < left_margin)
 
737
            left_margin = x;
 
738
          break;
 
739
        }
 
740
      
 
741
      for(x = 0; x < window->width; x++)
 
742
        if(window->text_buffer[i + window->width - x - 1] != ' ') {
 
743
          if(x < right_margin)
 
744
            right_margin = x;
 
745
          break;
 
746
        }
 
747
      
 
748
      i += window->width;
 
749
    }
 
750
    
 
751
    firstwidth = window->width; lastwidth = 0;
 
752
    
 
753
    if(start_line + 1 == end_line) {
 
754
      unsigned longestx = 0;
 
755
      unsigned longestlen = 0;
 
756
      unsigned thisx = 0;
 
757
      unsigned thislen = 0;
 
758
      colorstyle lastcolor;
 
759
      width = window->width;
 
760
      
 
761
      for(x = skipleft; x < width + skipleft; x++) {
 
762
        if(window->text_buffer[x] == ' '
 
763
           && (!thislen || coloreq(window->color_buffer[x], lastcolor))) {
 
764
          if(!thislen)
 
765
            thisx = x;
 
766
          thislen++;
 
767
          lastcolor = window->color_buffer[x];
 
768
        } else {
 
769
          if(thislen > longestlen) {
 
770
            longestx = thisx;
 
771
            longestlen = thislen;
 
772
          }
 
773
          thislen = 0;
 
774
        }
 
775
      }
 
776
      if(longestlen > 4) {
 
777
        firstwidth = longestx - skipleft;
 
778
        skipmiddle = longestlen - 1;
 
779
        lastwidth = width - firstwidth - skipmiddle;
 
780
      }
 
781
    }
 
782
    
 
783
    if(skipmiddle && winx < firstwidth + 2 + lastwidth)
 
784
      padmiddle = 2;
 
785
    
 
786
    if(lastwidth && winx >= firstwidth + padmiddle + lastwidth) {
 
787
      padmiddle = winx - firstwidth - lastwidth;
 
788
    } else {
 
789
      if(winx >= window->width)
 
790
        width = window->width;
 
791
      else
 
792
        width = winx;
 
793
      
 
794
      if(right_margin + left_margin) {
 
795
        if(winx > window->width)
 
796
          padleft = (unsigned) ((winx - window->width) * (((float) left_margin) / (right_margin + left_margin)));
 
797
        else
 
798
          skipleft = (unsigned) ((window->width - winx) * (((float) left_margin) / (right_margin + left_margin)));
 
799
      }
 
800
      else {
 
801
        padleft = winx - window->width;
 
802
      }
 
803
      
 
804
      if(skipleft > left_margin)
 
805
        skipleft = left_margin;
 
806
      
 
807
      if(winx > window->width)
 
808
        padright = winx - window->width - padleft;
 
809
      else
 
810
        skipright = window->width - winx - skipleft;
 
811
      
 
812
      if(width < firstwidth + padmiddle) {
 
813
        firstwidth = width;
 
814
        padmiddle = 0;
 
815
        lastwidth = 0;
 
816
      } else if(width < firstwidth + padmiddle + lastwidth) {
 
817
        lastwidth = width - firstwidth - padmiddle;
 
818
      }
 
819
    }
 
820
 
 
821
    
 
822
    glk_stream_set_current(window->str);
 
823
    glk_window_move_cursor(window->win, 0, start_line);
 
824
 
 
825
    /* draw to the upper window */
 
826
    i = 0;
 
827
    for(y = start_line; y < end_line; y++) {
 
828
 
 
829
      for(x = 0; x < padleft; x++)
 
830
        glk_put_char(' ');
 
831
 
 
832
      i += skipleft;
 
833
 
 
834
      z_put_styled_string(window, window->text_buffer + i,
 
835
                          window->color_buffer + i, firstwidth);
 
836
      i += firstwidth;
 
837
 
 
838
      for(x = 0; x < padmiddle; x++)
 
839
        glk_put_char(' ');
 
840
      i += skipmiddle;
 
841
      
 
842
      z_put_styled_string(window, window->text_buffer + i,
 
843
                          window->color_buffer + i, lastwidth);
 
844
      i += lastwidth;
 
845
 
 
846
      for(x = 0; x < padright; x++)
 
847
        glk_put_char(' ');
 
848
 
 
849
      i += skipright;
 
850
    }
 
851
 
 
852
    /* Bureaucracy needs the cursor positioned and visible in upper window. */
 
853
    glk_window_move_cursor(window->win,
 
854
                           window->curr_offset % window->width,
 
855
                           window->curr_offset / window->width);
 
856
    window->dirty = FALSE;
 
857
  }
 
858
}
 
859
 
 
860
 
 
861
void z_flush_text(zwinid window)
 
862
{
 
863
  z_pause_timed_input(window);
 
864
 
 
865
  if(!window->win || !window->str
 
866
     || !window->text_buffer || !window->color_buffer
 
867
     || window->curr_offset == 0) {
 
868
    window->curr_offset = 0;
 
869
    return;
 
870
  }
 
871
  
 
872
  z_put_styled_string(window, window->text_buffer, window->color_buffer,
 
873
                      window->curr_offset);
 
874
 
 
875
  window->curr_offset = 0;
 
876
  window->dirty = FALSE;
 
877
}
 
878
 
 
879
 
 
880
void z_flush_graphics(zwinid window)
 
881
{
 
882
  int i;
 
883
  glui32 winx, winy;
 
884
  float xratio, yratio;
 
885
  winid_t parent;
 
886
 
 
887
  if(!window->win)
 
888
    return;
 
889
 
 
890
  glk_window_get_size(window->win, &winx, &winy);
 
891
  xratio = ((float) winx) / window->width;
 
892
  yratio = ((float) winy) / window->height;
 
893
 
 
894
  parent = glk_window_get_parent(window->win);
 
895
 
 
896
  /* We want the window to maintain its original height/width ratio */
 
897
  switch(window->method & winmethod_DirMask) {
 
898
  case winmethod_Left:   /* Left and right splits mean height is fixed - */
 
899
  case winmethod_Right:  /* adjust width to the yratio */
 
900
    glk_window_set_arrangement(parent, window->method,
 
901
                               (glui32) (window->width * yratio), 0);
 
902
    break;
 
903
  case winmethod_Above:  /* Above and below splits mean width is fixed - */
 
904
  case winmethod_Below:  /* adjust height to the xratio */
 
905
    glk_window_set_arrangement(parent, window->method,
 
906
                               (glui32) (window->height * xratio), 0);
 
907
    break;
 
908
  }
 
909
 
 
910
  /* Check to see what it became, and if it's still off, don't worry */
 
911
  glk_window_get_size(window->win, &winx, &winy);
 
912
  xratio = ((float) winx) / window->width;
 
913
  yratio = ((float) winy) / window->height;
 
914
 
 
915
  for(i = 0; i < 12; i++) {
 
916
    if(window->images[i].image_num) {
 
917
      wrap_glk_image_draw_scaled(window->win, window->images[i].image_num,
 
918
                                 (glui32) (window->images[i].x * xratio),
 
919
                                 (glui32) (window->images[i].y * yratio),
 
920
                                 (glui32) (window->images[i].width * xratio),
 
921
                                 (glui32) (window->images[i].height * yratio));
 
922
    }
 
923
  }
 
924
}
 
925
 
 
926
void z_print_number(zwinid window, int number)
 
927
{
 
928
  int i;
 
929
  char buffer[12];
 
930
  int length = n_to_decimal(buffer, number);
 
931
 
 
932
  for(i = length - 1; i >= 0; i--)
 
933
    z_put_char(window, buffer[i]);
 
934
}
 
935
 
 
936
void z_put_char(zwinid window, unsigned c)
 
937
{
 
938
  colorstyle color = window->current;
 
939
  if(is_fixed)
 
940
    color.style |= sFIXE;
 
941
 
 
942
  if(c == 0)     /* Section 3.8.2.1 */
 
943
    return;
 
944
 
 
945
  window->dirty = TRUE;
 
946
 
 
947
  if((c < 32 && c != 13) || (c >= 127 && c <= 159)) {  /*Undefined in latin-1*/
 
948
    switch(window->wintype) {
 
949
    case wintype_TextBuffer:
 
950
      z_put_char(window, '[');
 
951
      z_print_number(window, c);
 
952
      z_put_char(window, ']');
 
953
      return;
 
954
    case wintype_TextGrid:
 
955
      c = '?';
 
956
    }
 
957
  }
 
958
 
 
959
  switch(c) {
 
960
  case 0x152:
 
961
    z_put_char(window, 'O');
 
962
    c = 'E';
 
963
    break;
 
964
  case 0x153:
 
965
    z_put_char(window, 'o');
 
966
    c = 'e';
 
967
    break;
 
968
  }
 
969
 
 
970
 
 
971
  if(c > 255)    /* Section 3.8.5.4.3 */
 
972
    c = '?';
 
973
 
 
974
  if(c == 13) {  /* Section 7.1.2.2.1 */
 
975
    switch(window->wintype) {
 
976
    case wintype_TextBuffer:
 
977
      window->text_buffer[window->curr_offset] = 10;
 
978
      window->curr_offset++;
 
979
      z_flush_text(window);
 
980
      break;
 
981
    case wintype_TextGrid:
 
982
      window->curr_offset += window->width;
 
983
      window->curr_offset -= window->curr_offset % window->width;
 
984
    }
 
985
  } else {
 
986
    window->text_buffer[window->curr_offset] = c;
 
987
    window->color_buffer[window->curr_offset] = color;
 
988
    window->curr_offset++;
 
989
  }
 
990
 
 
991
  if(window->curr_offset >= window->max_offset) {
 
992
    switch(window->wintype) {
 
993
    case wintype_TextBuffer:
 
994
      z_flush_text(window);
 
995
      break;
 
996
    case wintype_TextGrid:
 
997
      if(!window->defined)                  /* Section 8.6.2 */
 
998
        n_show_port(E_OUTPUT, "writing past end of window", c);
 
999
      
 
1000
      if(window->max_offset)
 
1001
        window->curr_offset = window->max_offset - 1;
 
1002
      else
 
1003
        window->curr_offset = 0;
 
1004
 
 
1005
      window->defined = FALSE;
 
1006
    }
 
1007
  }
 
1008
}
 
1009
 
 
1010
void z_setxy(zwinid window, zword x, zword y)
 
1011
{
 
1012
  window->curr_offset = (y - 1) * window->width + (x - 1);
 
1013
  window->defined = TRUE;
 
1014
}
 
1015
 
 
1016
void z_getxy(zwinid window, zword *x, zword *y)
 
1017
{
 
1018
  if(window->width) {
 
1019
    *x = (window->curr_offset % window->width) + 1;
 
1020
    *y = (window->curr_offset / window->width) + 1;
 
1021
  } else {
 
1022
    *x = window->curr_offset + 1;
 
1023
    *y = 1;
 
1024
  }
 
1025
}
 
1026
 
 
1027
void z_getsize(zwinid window, unsigned *width, unsigned *height)
 
1028
{
 
1029
  *width = window->width;
 
1030
  *height = window->height;
 
1031
}
 
1032
 
 
1033
void z_find_size(glui32 *wid, glui32 *hei)
 
1034
{
 
1035
  glui32 oldwid, oldhei;
 
1036
  zwinid upper = &game_windows[1];
 
1037
  winid_t o = glk_window_get_parent(upper->win);
 
1038
  glk_window_get_size(upper->win, &oldwid, &oldhei);
 
1039
  glk_window_set_arrangement(o, (upper->method & ~winmethod_Fixed) |
 
1040
                             winmethod_Proportional, 100, upper->win);
 
1041
  glk_window_get_size(upper->win, wid, hei);
 
1042
  glk_window_set_arrangement(o, upper->method, oldhei, upper->win);
 
1043
 
 
1044
  upper_width = *wid; upper_height = *hei;
 
1045
  init_upper(&upper);
 
1046
}
 
1047
 
 
1048
void z_set_height(zwinid window, unsigned height)
 
1049
{
 
1050
  unsigned x;
 
1051
  if(height * window->width > window->buffer_size) {
 
1052
    n_show_error(E_OUTPUT, "height too large", height);
 
1053
    return;
 
1054
  }
 
1055
 
 
1056
  window->height = height;
 
1057
  if(height > window->biggest_height)
 
1058
    window->biggest_height = height;
 
1059
 
 
1060
  x = window->max_offset;
 
1061
  window->max_offset = height * window->width;
 
1062
 
 
1063
  for(; x < window->max_offset; x++) {
 
1064
    window->text_buffer[x] = ' ';
 
1065
    window->color_buffer[x] = window->current;
 
1066
  }
 
1067
 
 
1068
  window->dirty = TRUE;
 
1069
}
 
1070
 
 
1071
void z_set_color(zwinid window, unsigned fore, unsigned back)
 
1072
{
 
1073
  if(fore >= sizeof(fgcolortable) / sizeof(*fgcolortable)) {
 
1074
    n_show_error(E_OUTPUT, "illegal foreground color", fore);
 
1075
    return;
 
1076
  }
 
1077
  if(back >= sizeof(bgcolortable) / sizeof(*bgcolortable)) {
 
1078
    n_show_error(E_OUTPUT, "illegal background color", back);
 
1079
    return;
 
1080
  }
 
1081
 
 
1082
  fgcolortable[0] = fgcolortable[fore];
 
1083
  bgcolortable[0] = bgcolortable[back];
 
1084
  
 
1085
  window->current.fore = fore;
 
1086
  window->current.back = back;
 
1087
}
 
1088
 
 
1089
void z_set_style(zwinid window, int style)
 
1090
{
 
1091
  switch(style) {
 
1092
  case 0: window->current.style = 0; break;
 
1093
  case 1: window->current.style |= sREVE; break;
 
1094
  case 2: window->current.style |= sBOLD; break;
 
1095
  case 4: window->current.style |= sITAL; break;
 
1096
  case 8: window->current.style |= sFIXE; break;
 
1097
  default: n_show_error(E_OUTPUT, "undefined style", style);
 
1098
  }
 
1099
}
 
1100
 
 
1101
void set_fixed(BOOL p)
 
1102
{
 
1103
  if(!p) {
 
1104
    is_fixed = FALSE;
 
1105
  } else {
 
1106
    is_fixed = TRUE;
 
1107
  }
 
1108
}
 
1109
 
 
1110
void z_set_transcript(zwinid window, strid_t stream)
 
1111
{
 
1112
  window->transcript = stream;
 
1113
  glk_window_set_echo_stream(window->win, stream);
 
1114
}
 
1115
 
 
1116
void z_clear_window(zwinid window)
 
1117
{
 
1118
  glui32 i;
 
1119
 
 
1120
  if(window == &game_windows[0] && showstuffcount) {
 
1121
    z_pause_timed_input(&game_windows[0]);
 
1122
    z_flush_text(&game_windows[0]);
 
1123
    glk_stream_set_current(game_windows[0].str);
 
1124
    w_glk_put_string("[pausing to show unread error message]\n");
 
1125
    z_wait_for_key(&game_windows[0]);
 
1126
  }
 
1127
 
 
1128
  window->dirty = TRUE;
 
1129
  window->curr_offset = 0;
 
1130
 
 
1131
  if(window->win && window->text_buffer && window->color_buffer) {
 
1132
    switch(window->wintype) {
 
1133
    case wintype_TextGrid:
 
1134
      for(i = 0; i < window->max_offset; i++) {
 
1135
        window->text_buffer[i] = ' ';
 
1136
        window->color_buffer[i] = window->current;
 
1137
      }
 
1138
      window->curr_offset = 0;
 
1139
      window->dirty = TRUE;
 
1140
      break;
 
1141
    case wintype_TextBuffer:
 
1142
      z_pause_timed_input(window);
 
1143
      z_flush_text(window);
 
1144
      if(coloreq(window->actual, window->current)) {
 
1145
        glk_window_clear(window->win);
 
1146
      } else {
 
1147
        init_lower(NULL); /* **FIXME** This is wrong, but deal with it later */
 
1148
      }
 
1149
    }
 
1150
  }
 
1151
}
 
1152
 
 
1153
void z_erase_line(zwinid window)
 
1154
{
 
1155
  if(window->wintype == wintype_TextGrid) {
 
1156
    int i;
 
1157
    int x = window->curr_offset % window->width;
 
1158
    int endoffset = window->curr_offset + (window->width - x);
 
1159
    
 
1160
    window->dirty = TRUE;
 
1161
    for(i = window->curr_offset; i < endoffset; i++) {
 
1162
      window->text_buffer[i] = ' ';
 
1163
      window->color_buffer[i] = window->current;
 
1164
    }
 
1165
  }
 
1166
}
 
1167
 
 
1168
 
 
1169
/* Waits for input or timeout
 
1170
 * Returns:
 
1171
 *   0 - output during wait; may need to redraw or somesuch
 
1172
 *  -1 - callback routine said to stop
 
1173
 *  10 - read input
 
1174
 * 254 - mouse input
 
1175
 * char and line events will be canceled by the time it exits
 
1176
 */
 
1177
static int waitforinput(zwinid window, glui32 *val,
 
1178
                        BOOL (*timer_callback)(zword), zword timer_arg)
 
1179
{
 
1180
  int i;
 
1181
  event_t moo;
 
1182
  zwinid t;
 
1183
  
 
1184
  showstuffcount = 0;
 
1185
 
 
1186
  for(i = 0; i < num_z_windows; i++)
 
1187
    if(game_windows[i].mouse_callback && game_windows[i].win)
 
1188
      glk_request_mouse_event(game_windows[i].win);
 
1189
  
 
1190
  window->glk_input_pending = TRUE;
 
1191
 
 
1192
  while(window->glk_input_pending) {
 
1193
    glk_select(&moo);
 
1194
 
 
1195
    check_sound(moo);
 
1196
 
 
1197
    switch(moo.type) {
 
1198
    case evtype_Timer:
 
1199
      if(timer_callback && timer_callback(timer_arg)) {
 
1200
        if(window->pending_input_type == evtype_CharInput) {
 
1201
          glk_cancel_char_event(window->win);
 
1202
          *val = 0;
 
1203
        } else {
 
1204
          glk_cancel_line_event(window->win, &moo);
 
1205
          *val = moo.val1;
 
1206
        }
 
1207
        window->glk_input_pending = FALSE;
 
1208
        return -1;
 
1209
      }
 
1210
      break;
 
1211
 
 
1212
    case evtype_CharInput:
 
1213
      *val = moo.val1;
 
1214
      window->glk_input_pending = FALSE;
 
1215
      return 10;
 
1216
 
 
1217
    case evtype_LineInput:
 
1218
      *val = moo.val1;
 
1219
      window->glk_input_pending = FALSE;
 
1220
      return 10;
 
1221
 
 
1222
    case evtype_MouseInput:
 
1223
      t = z_find_win(moo.win);
 
1224
      if(t && t->mouse_callback &&
 
1225
         t->mouse_callback(window->pending_input_type == evtype_CharInput,
 
1226
                           moo.win, moo.val1, moo.val2)) {
 
1227
        if(window->pending_input_type == evtype_CharInput) {
 
1228
          glk_cancel_char_event(window->win);
 
1229
          *val = 254;
 
1230
        } else {
 
1231
          glk_cancel_line_event(window->win, &moo);
 
1232
          *val = moo.val1;
 
1233
        }
 
1234
        window->glk_input_pending = FALSE;
 
1235
        return 254;
 
1236
      }
 
1237
      glk_request_mouse_event(moo.win);
 
1238
      break;
 
1239
    
 
1240
    case evtype_Arrange:
 
1241
      z_draw_all_windows();
 
1242
    }
 
1243
 
 
1244
    z_flush_all_windows();
 
1245
  }
 
1246
 
 
1247
  if(window->pending_input_type == evtype_LineInput)
 
1248
    *val = window->pending_input_length;
 
1249
  else
 
1250
    *val = 0;
 
1251
 
 
1252
  return 0;
 
1253
}
 
1254
 
 
1255
 
 
1256
void z_wait_for_key(zwinid window)
 
1257
{
 
1258
  glui32 ch;
 
1259
  do {
 
1260
    z_draw_all_windows();
 
1261
    glk_request_char_event(window->win);
 
1262
    window->pending_input_type = evtype_CharInput;
 
1263
  } while(waitforinput(window, &ch, NULL, 0) == 0);
 
1264
  window->pending_input_type = 0;
 
1265
}
 
1266
 
 
1267
 
 
1268
zwinid check_valid_for_input(zwinid window)
 
1269
{  
 
1270
  glui32 y, i;
 
1271
  if(!window->win) {
 
1272
    zwinid newwin = NULL;
 
1273
    for(i = 0; i < num_z_windows; i++) {
 
1274
      if(game_windows[i].win) {
 
1275
        newwin = &game_windows[i];
 
1276
        break;
 
1277
      }
 
1278
    }
 
1279
    if(!newwin)
 
1280
      return NULL;
 
1281
 
 
1282
    if(window->wintype == wintype_TextGrid) {
 
1283
      i = 0;
 
1284
      for(y = 0; y < window->height; y++) {
 
1285
        z_put_char(newwin, 13);
 
1286
        z_put_styled_string(newwin, window->text_buffer + i,
 
1287
                            window->color_buffer + i, window->width);
 
1288
        i += window->width;
 
1289
      }
 
1290
      z_put_char(newwin, 13);
 
1291
    }
 
1292
 
 
1293
    window = newwin;
 
1294
  }
 
1295
  return window;
 
1296
}
 
1297
 
 
1298
 
 
1299
/* returns number of characters read */
 
1300
int z_read(zwinid window, char *dest, unsigned maxlen, unsigned initlen,
 
1301
           zword timer, BOOL (*timer_callback)(zword), zword timer_arg,
 
1302
           unsigned char *terminator)
 
1303
{
 
1304
  /* FIXME: support terminating characters when (if) glk gets support for
 
1305
     them */
 
1306
  unsigned i;
 
1307
  unsigned ux, uy;
 
1308
  glui32 length;
 
1309
  BOOL done;
 
1310
 
 
1311
  if(automap_unexplore()) {
 
1312
    read_abort = TRUE;
 
1313
    return 0;
 
1314
  }
 
1315
  
 
1316
  read_abort = FALSE;
 
1317
 
 
1318
  if(initlen > maxlen) {
 
1319
    n_show_error(E_OUTPUT, "initlen > maxlen", initlen);
 
1320
    return 0;
 
1321
  }
 
1322
 
 
1323
  if(window == 0)
 
1324
    window = &game_windows[0];
 
1325
  
 
1326
  if(window->pending_input_type != 0) {
 
1327
    n_show_error(E_OUTPUT, "nested input attempted", 0);
 
1328
    return 0;
 
1329
  }
 
1330
 
 
1331
#ifdef DEBUGGING
 
1332
 
 
1333
  if(do_automap) {
 
1334
    const char *dir = automap_explore();
 
1335
    if(dir) {
 
1336
      length = n_strlen(dir);
 
1337
      if(length > maxlen)
 
1338
        length = maxlen;
 
1339
      n_strncpy(dest, dir, length);
 
1340
      return length;
 
1341
    }
 
1342
  }
 
1343
#endif
 
1344
 
 
1345
  glk_request_timer_events(timer * 100);  /* if time is zero, does nothing */
 
1346
    
 
1347
  if(initlen != 0 && window->wintype == wintype_TextBuffer) {
 
1348
    BOOL good = FALSE;
 
1349
    if(initlen <= window->curr_offset) {
 
1350
      good = TRUE;
 
1351
      for(i = 0; i < initlen; i++)  /* check the end of the linebuffer */
 
1352
        if(window->text_buffer[window->curr_offset - initlen + i] != dest[i]) {
 
1353
          good = FALSE;
 
1354
          break;
 
1355
        }
 
1356
    }
 
1357
    if(!good) {
 
1358
      /* bleah */
 
1359
      /* argh */
 
1360
      /* oof */
 
1361
    } else {
 
1362
      window->curr_offset -= initlen; /* Remove initial text from linebuffer */
 
1363
    }
 
1364
  }
 
1365
  
 
1366
  if(window->wintype == wintype_TextGrid) {
 
1367
    ux = window->curr_offset % window->width;
 
1368
    uy = window->curr_offset / window->width;
 
1369
  }
 
1370
 
 
1371
  z_flush_all_windows();
 
1372
  window = check_valid_for_input(window);
 
1373
 
 
1374
  done = FALSE;
 
1375
  length = initlen;
 
1376
  while(!done) {
 
1377
    int t;
 
1378
 
 
1379
    if(window->wintype == wintype_TextGrid)
 
1380
      glk_window_move_cursor(window->win, ux, uy);
 
1381
 
 
1382
    if(input_stream1) {
 
1383
      glui32 len = maxlen;
 
1384
      *terminator = transcript_getline(dest, &len);
 
1385
      length = len;
 
1386
    }
 
1387
    if(input_stream1) { /* If didn't EOF, input_stream1 will be non-zero */
 
1388
      glk_stream_set_current(window->str);
 
1389
      set_glk_stream_current();
 
1390
      glk_set_style(style_Input);
 
1391
      glk_put_buffer(dest, length);
 
1392
      glk_put_char(10);
 
1393
      done = TRUE;
 
1394
    } else {
 
1395
      glk_request_line_event(window->win, dest, maxlen, length);
 
1396
      window->pending_input_type = evtype_LineInput;
 
1397
    
 
1398
      t = waitforinput(window, &length, timer_callback, timer_arg);
 
1399
      if(t != 0) {
 
1400
        if(t == -1)
 
1401
          *terminator = 0;
 
1402
        else
 
1403
          *terminator = t;
 
1404
        done = TRUE;
 
1405
      }
 
1406
    }
 
1407
 
 
1408
    if(done)
 
1409
      stream4line(dest, length, *terminator);
 
1410
 
 
1411
#ifdef DEBUGGING
 
1412
    if(done && length >= 2 && dest[0] == '/') {
 
1413
      if(dest[1] == '/') {  /* "//" means no command, but start with "/" */
 
1414
        for(i = 1; i < length; i++)
 
1415
          dest[i-1] = dest[i];
 
1416
        length--;
 
1417
      } else {
 
1418
        done = FALSE;
 
1419
        dest[length] = 0;
 
1420
        
 
1421
        process_debug_command(dest+1);
 
1422
 
 
1423
        if(read_abort)
 
1424
          done = TRUE;
 
1425
 
 
1426
        length = 0;
 
1427
      }
 
1428
    }
 
1429
#endif
 
1430
  }
 
1431
  glk_request_timer_events(0);  /* stop timer */
 
1432
 
 
1433
  window->pending_input_type = 0;
 
1434
 
 
1435
  for(i = 0; i < num_z_windows; i++)
 
1436
    game_windows[i].biggest_height = game_windows[i].last_height = game_windows[i].height;
 
1437
 
 
1438
  return length;
 
1439
}
 
1440
 
 
1441
zword z_read_char(zwinid window,
 
1442
                  zword timer, BOOL (*timer_callback)(zword), zword timer_arg)
 
1443
{
 
1444
  unsigned i;
 
1445
  glui32 ch;
 
1446
  zword validch = 0;
 
1447
 
 
1448
  if(automap_unexplore()) {
 
1449
    read_abort = TRUE;
 
1450
    return 0;
 
1451
  }
 
1452
 
 
1453
  if(input_stream1) {
 
1454
    unsigned num;
 
1455
    validch = transcript_getchar(&num);
 
1456
    if(!validch)
 
1457
      validch = num;
 
1458
  }
 
1459
  if(input_stream1) {
 
1460
    return validch;
 
1461
  }
 
1462
  
 
1463
  read_abort = FALSE;
 
1464
 
 
1465
  glk_request_timer_events(timer * 100);
 
1466
 
 
1467
  z_flush_all_windows();
 
1468
  window = check_valid_for_input(window);
 
1469
 
 
1470
  do {
 
1471
    do {
 
1472
      z_draw_all_windows();
 
1473
      glk_request_char_event(window->win);
 
1474
      window->pending_input_type = evtype_CharInput;
 
1475
    } while(waitforinput(window, &ch, timer_callback, timer_arg) == 0);
 
1476
    
 
1477
    if(' ' <= ch && ch <= '~')
 
1478
      validch = ch;
 
1479
    
 
1480
    switch(ch) {
 
1481
    case 8:
 
1482
    case keycode_Delete: validch = 8; break;
 
1483
    case 9:
 
1484
    case keycode_Tab:    validch = 9; break;
 
1485
    case 13:
 
1486
    case keycode_Return: validch = 13; break;
 
1487
/*  case 21:
 
1488
      if(restoreundo()) {
 
1489
        read_abort = TRUE;
 
1490
        return 0;
 
1491
      }
 
1492
      break; */
 
1493
    case 27:
 
1494
    case keycode_Escape: validch = 27; break;
 
1495
    case 16:
 
1496
    case keycode_Up:     validch = 129; break;
 
1497
    case 14:
 
1498
    case keycode_Down:   validch = 130; break;
 
1499
    case 2:
 
1500
    case keycode_Left:   validch = 131; break;
 
1501
    case 6:
 
1502
    case keycode_Right:  validch = 132; break;
 
1503
    case keycode_Func1:  validch = 133; break;
 
1504
    case keycode_Func2:  validch = 134; break;
 
1505
    case keycode_Func3:  validch = 135; break;
 
1506
    case keycode_Func4:  validch = 136; break;
 
1507
    case keycode_Func5:  validch = 137; break;
 
1508
    case keycode_Func6:  validch = 138; break;
 
1509
    case keycode_Func7:  validch = 139; break;
 
1510
    case keycode_Func8:  validch = 140; break;
 
1511
    case keycode_Func9:  validch = 141; break;
 
1512
    case keycode_Func10: validch = 142; break;
 
1513
    case keycode_Func11: validch = 143; break;
 
1514
    case keycode_Func12: validch = 144; break;
 
1515
    }
 
1516
  } while(!(validch || ch == 0));
 
1517
 
 
1518
  glk_request_timer_events(0);     /* stop timer */
 
1519
 
 
1520
  window->pending_input_type = 0;
 
1521
 
 
1522
  for(i = 0; i < num_z_windows; i++)
 
1523
    game_windows[i].biggest_height = game_windows[i].last_height = game_windows[i].height;
 
1524
 
 
1525
  return validch;
 
1526
}
 
1527
 
 
1528
 
 
1529
/*
 
1530
void zwin_init(int number, glui32 wintype,
 
1531
               glui32 x_coord, glui32 y_coord, glui32 x_size, glui32 y_size)
 
1532
{
 
1533
  zwinid self = game_windows + number;
 
1534
 
 
1535
  if(x_coord == self->x1) {
 
1536
    if(y_coord == self->y1) {
 
1537
      
 
1538
 
 
1539
  if(game_windows[number].win) {
 
1540
    z_pause_timed_input(game_windows[number].win);
 
1541
    glk_window_close(game_windows[number].win, NULL);
 
1542
  }
 
1543
  set_style_hints();
 
1544
  game_windows[number].win = glk_window_open(
 
1545
}
 
1546
*/