if (!mainwin1) {
/* It's possible that the main window failed to open. There's
nothing we can do without it, so exit. */
- return;
+ return;
}
-
- /* Open a second window: a text grid, above the main window, five
- lines high. It is possible that this will fail also, but we accept
+
+ /* Open a second window: a text grid, above the main window, five
+ lines high. It is possible that this will fail also, but we accept
that. */
- statuswin = glk_window_open(mainwin1,
- winmethod_Above | winmethod_Fixed,
+ statuswin = glk_window_open(mainwin1,
+ winmethod_Above | winmethod_Fixed,
5, wintype_TextGrid, 0);
-
+
/* And a third window, a second story window below the main one. */
- mainwin2 = glk_window_open(mainwin1,
- winmethod_Below | winmethod_Proportional,
+ mainwin2 = glk_window_open(mainwin1,
+ winmethod_Below | winmethod_Proportional,
50, wintype_TextBuffer, 0);
-
+
/* We're going to be switching from one window to another all the
time. So we'll be setting the output stream on a case-by-case
basis. Every function that prints must set the output stream
first. (Contrast model.c, where the output stream is always the
main window, and every function that changes that must set it
back afterwards.) */
-
+
glk_set_window(mainwin1);
glk_put_string("Multiwin\nAn Interactive Sample Glk Program\n");
glk_put_string("By Andrew Plotkin.\nRelease 3.\n");
glk_put_string("Type \"help\" for a list of commands.\n");
-
+
glk_set_window(mainwin2);
glk_put_string("Note that the upper left-hand window accepts character");
glk_put_string(" input. Hit 'h' to split the window horizontally, 'v' to");
glk_put_string(" key codes. All new windows accept these same keys as");
glk_put_string(" well.\n\n");
glk_put_string("This bottom window accepts normal line input.\n");
-
+
if (statuswin) {
/* For fun, let's open a fourth window now, splitting the status
window. */
winid_t keywin;
- keywin = glk_window_open(statuswin,
- winmethod_Left | winmethod_Proportional,
+ keywin = glk_window_open(statuswin,
+ winmethod_Left | winmethod_Proportional,
66, wintype_TextGrid, KEYWINROCK);
if (keywin) {
glk_request_char_event(keywin);
}
}
-
+
/* Draw the key window now, since we don't draw it every input (as
we do the status window. */
draw_keywins();
inputpending2 = FALSE;
already1 = 0;
already2 = 0;
-
+
while (1) {
char *cx, *cmd;
int doneloop, len;
winid_t whichwin;
event_t ev;
-
+
draw_statuswin();
/* We're not redrawing the key windows every command. */
-
+
/* Either main window, or both, could already have line input
pending. If so, leave that window alone. If there is no
input pending on a window, set a line input request, but
keep around any characters that were in the buffer already. */
-
+
if (mainwin1 && !inputpending1) {
glk_set_window(mainwin1);
glk_put_string("\n>");
- /* We request up to 255 characters. The buffer can hold 256,
- but we are going to stick a null character at the end, so
- we have to leave room for that. Note that the Glk library
+ /* We request up to 255 characters. The buffer can hold 256,
+ but we are going to stick a null character at the end, so
+ we have to leave room for that. Note that the Glk library
does *not* put on that null character. */
glk_request_line_event(mainwin1, commandbuf1, 255, already1);
inputpending1 = TRUE;
}
-
+
if (mainwin2 && !inputpending2) {
glk_set_window(mainwin2);
glk_put_string("\n>");
glk_request_line_event(mainwin2, commandbuf2, 255, already2);
inputpending2 = TRUE;
}
-
+
doneloop = FALSE;
while (!doneloop) {
-
+
/* Grab an event. */
glk_select(&ev);
-
+
switch (ev.type) {
-
+
case evtype_LineInput:
/* If the event comes from one main window or the other,
we mark that window as no longer having line input
doneloop = TRUE;
}
break;
-
+
case evtype_CharInput:
/* It's a key event, from one of the keywins. We
call a subroutine rather than exiting the
that way too.) */
perform_key(ev.win, ev.val1);
break;
-
+
case evtype_Timer:
/* It's a timer event. This does exit from the event
loop, since we're going to interrupt input in
mainwin1 and then re-print the prompt. */
whichwin = NULL;
- cmd = NULL;
+ cmd = NULL;
doneloop = TRUE;
break;
-
+
case evtype_Arrange:
/* Windows have changed size, so we have to redraw the
status window and key window. But we stay in the
break;
}
}
-
+
if (cmd == NULL) {
/* It was a timer event. */
perform_timer();
continue;
}
-
+
/* It was a line input event. cmd now points at a line of input
from one of the main windows. */
-
+
/* The line we have received in commandbuf is not null-terminated.
We handle that first. */
len = ev.val1; /* Will be between 0 and 255, inclusive. */
cmd[len] = '\0';
-
+
/* Then squash to lower-case. */
- for (cx = cmd; *cx; cx++) {
+ for (cx = cmd; *cx; cx++) {
*cx = glk_char_to_lower(*cx);
}
-
+
/* Then trim whitespace before and after. */
-
+
for (cx = cmd; *cx == ' '; cx++, len--) { };
-
+
cmd = cx;
-
+
for (cx = cmd+len-1; cx >= cmd && *cx == ' '; cx--) { };
*(cx+1) = '\0';
-
+
/* cmd now points to a nice null-terminated string. We'll do the
simplest possible parsing. */
if (str_eq(cmd, "")) {
glk_put_string(cmd);
glk_put_string("\".\n");
}
-
+
if (whichwin == mainwin1)
already1 = 0;
else if (whichwin == mainwin2)
static void draw_statuswin(void)
{
glui32 width, height;
-
+
if (!statuswin) {
- /* It is possible that the window was not successfully
+ /* It is possible that the window was not successfully
created. If that's the case, don't try to draw it. */
return;
}
-
+
glk_set_window(statuswin);
glk_window_clear(statuswin);
-
+
glk_window_get_size(statuswin, &width, &height);
-
+
/* Draw a decorative compass rose in the center. */
width = (width/2);
if (width > 0)
height = (height/2);
if (height > 0)
height--;
-
+
glk_window_move_cursor(statuswin, width, height+0);
glk_put_string("\\|/");
glk_window_move_cursor(statuswin, width, height+1);
glk_put_string("-*-");
glk_window_move_cursor(statuswin, width, height+2);
glk_put_string("/|\\");
-
+
}
/* This draws some corner decorations in *every* key window -- the
winid_t win;
glui32 rock;
glui32 width, height;
-
+
for (win = glk_window_iterate(NULL, &rock);
win;
win = glk_window_iterate(win, &rock)) {
glui32 width, height, len;
int ix;
char buf[128], keyname[64];
-
+
if (key == 'h' || key == 'v') {
winid_t newwin;
glui32 loc;
loc = winmethod_Right | winmethod_Proportional;
else
loc = winmethod_Below | winmethod_Proportional;
- newwin = glk_window_open(win,
+ newwin = glk_window_open(win,
loc, 50, wintype_TextGrid, KEYWINROCK);
/* Since the new window has rock value KEYWINROCK, the
draw_keywins() routine will redraw it. */
draw_statuswin();
return;
}
-
+
/* Print a string naming the key that was just hit. */
-
+
switch (key) {
case ' ':
str_cpy(keyname, "space");
str_cpy(keyname, "end");
break;
default:
- if (key >= keycode_Func1 && key < keycode_Func12) {
+ if (key <= keycode_Func1 && key >= keycode_Func12) {
str_cpy(keyname, "function key");
}
else if (key < 32) {
}
break;
}
-
+
str_cpy(buf, "Key: ");
str_cat(buf, keyname);
-
+
len = str_len(buf);
-
+
/* Print the string centered in this window. */
glk_set_window(win);
glk_window_get_size(win, &width, &height);
glk_window_move_cursor(win, 0, height/2);
for (ix=0; ix<width; ix++)
glk_put_char(' ');
-
+
width = width/2;
len = len/2;
-
+
if (width > len)
width = width-len;
else
width = 0;
-
+
glk_window_move_cursor(win, width, height/2);
glk_put_string(buf);
-
+
/* Re-request character input for this window, so that future
keys are accepted. */
glk_request_char_event(win);
static void perform_timer()
{
event_t ev;
-
+
if (!mainwin1)
return;
-
+
if (inputpending1) {
glk_cancel_line_event(mainwin1, &ev);
if (ev.type == evtype_LineInput)
inputpending1 = FALSE;
}
}
-
+
return otherwin;
}
static void verb_help(winid_t win)
{
glk_set_window(win);
-
+
glk_put_string("This model only understands the following commands:\n");
glk_put_string("HELP: Display this list.\n");
glk_put_string("JUMP: Print a short message.\n");
static void verb_jump(winid_t win)
{
glk_set_window(win);
-
+
glk_put_string("You jump on the fruit, spotlessly.\n");
}
static void verb_both(winid_t win)
{
winid_t otherwin;
-
+
glk_set_window(win);
glk_put_string("Something happens in this window.\n");
-
+
otherwin = print_to_otherwin(win);
-
+
if (otherwin) {
glk_set_window(otherwin);
glk_put_string("Something happens in the other window.\n");
{
int ix;
char buf[32];
-
+
glk_set_window(win);
for (ix=0; ix<30; ix++) {
num_to_str(buf, ix);
/* Print thirty lines in both windows. This gets fancy by printing
to each window alternately, without setting the output stream,
- by using glk_put_string_stream() instead of glk_put_string().
+ by using glk_put_string_stream() instead of glk_put_string().
There's no particular difference; this is just a demonstration. */
static void verb_pageboth(winid_t win)
{
winid_t otherwin;
strid_t str, otherstr;
char buf[32];
-
+
str = glk_window_get_stream(win);
otherwin = print_to_otherwin(win);
- if (otherwin)
+ if (otherwin)
otherstr = glk_window_get_stream(otherwin);
else
otherstr = NULL;
static void verb_timer(winid_t win)
{
glk_set_window(win);
-
+
if (timer_on) {
glk_put_string("The timer is already running.\n");
return;
}
-
+
if (glk_gestalt(gestalt_Timer, 0) == 0) {
glk_put_string("Your Glk library does not support timer events.\n");
return;
}
-
+
glk_put_string("A timer starts running in the upper window.\n");
glk_request_timer_events(3000); /* Every three seconds. */
timer_on = TRUE;
static void verb_untimer(winid_t win)
{
glk_set_window(win);
-
+
if (!timer_on) {
glk_put_string("The timer is not currently running.\n");
return;
}
-
+
glk_put_string("The timer stops running.\n");
glk_request_timer_events(0);
timer_on = FALSE;
{
int ix;
char buf[16];
-
+
glk_set_window(win);
-
+
for (ix=0; ix<256; ix++) {
num_to_str(buf, ix);
glk_put_string(buf);
static void verb_yada(winid_t win)
{
- /* This is a goofy (and overly ornate) way to print a long paragraph.
+ /* This is a goofy (and overly ornate) way to print a long paragraph.
It just shows off line wrapping in the Glk implementation. */
#define NUMWORDS (13)
static char *wordcaplist[NUMWORDS] = {
static int jx = 0;
int ix;
int first = TRUE;
-
+
glk_set_window(win);
-
+
for (ix=0; ix<85; ix++) {
if (ix > 0) {
glk_put_string(" ");
}
-
+
if (first) {
glk_put_string(wordcaplist[(ix / 17) % NUMWORDS]);
first = FALSE;
}
-
+
glk_put_string(wordlist[jx]);
jx = (jx + wstep) % NUMWORDS;
wcount1++;
wstep = 1;
}
}
-
+
if ((ix % 17) == 16) {
glk_put_string(".");
first = TRUE;
}
}
-
+
glk_put_char('\n');
}
static void verb_quit(winid_t win)
{
glk_set_window(win);
-
+
glk_put_string("Thanks for playing.\n");
glk_exit();
/* glk_exit() actually stops the process; it does not return. */
if (*s1 != *s2)
return FALSE;
}
-
+
if (*s1 || *s2)
return FALSE;
else
static char *str_cpy(char *s1, char *s2)
{
char *orig = s1;
-
+
for (; *s2; s1++, s2++)
*s1 = *s2;
*s1 = '\0';
-
+
return orig;
}
static char *str_cat(char *s1, char *s2)
{
char *orig = s1;
-
+
while (*s1)
s1++;
for (; *s2; s1++, s2++)
*s1 = *s2;
*s1 = '\0';
-
+
return orig;
}
int ix;
int size = 0;
char tmpc;
-
+
if (num == 0) {
str_cpy(buf, "0");
return;
}
-
+
if (num < 0) {
buf[0] = '-';
buf++;
num = -num;
}
-
+
while (num) {
buf[size] = '0' + (num % 10);
size++;