X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=src%2Fmultiwin.c;fp=src%2Fmultiwin.c;h=0000000000000000000000000000000000000000;hb=0b85f1dd5993e2ed111ec2ba13bbbb4ebda06ada;hp=261d7fbc8895274789792467975749d480fd2580;hpb=08f8444e2ae5480eea1cf7e2c1e2eb57f46152db;p=rodin%2Fchimara.git diff --git a/src/multiwin.c b/src/multiwin.c deleted file mode 100644 index 261d7fb..0000000 --- a/src/multiwin.c +++ /dev/null @@ -1,843 +0,0 @@ -#include "glk.h" - -/* multiwin.c: Sample program for Glk API, version 0.5. - Designed by Andrew Plotkin - http://www.eblong.com/zarf/glk/index.html - This program is in the public domain. -*/ - -/* This example demonstrates multiple windows and timed input in the - Glk API. */ - -/* This is the cleanest possible form of a Glk program. It includes only - "glk.h", and doesn't call any functions outside Glk at all. We even - define our own string functions, rather than relying on the - standard libraries. */ - -/* We also define our own TRUE and FALSE and NULL. */ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef NULL -#define NULL 0 -#endif - -/* The story and status windows. */ -static winid_t mainwin1 = NULL; -static winid_t mainwin2 = NULL; -static winid_t statuswin = NULL; - -/* Key windows don't get stored in a global variable; we'll find them - by iterating over the list and looking for this rock value. */ -#define KEYWINROCK (97) - -/* For the two main windows, we keep a flag saying whether that window - has a line input request pending. (Because if it does, we need to - cancel the line input before printing to that window.) */ -static int inputpending1, inputpending2; -/* When we cancel line input, we should remember how many characters - had been typed. This lets us restart the input with those characters - already in place. */ -static int already1, already2; - -/* There's a three-second timer which can be on or off. */ -static int timer_on = FALSE; - -/* Forward declarations */ -void glk_main(void); - -static void draw_statuswin(void); -static void draw_keywins(void); -static void perform_key(winid_t win, glui32 key); -static void perform_timer(void); - -static int str_eq(char *s1, char *s2); -static int str_len(char *s1); -static char *str_cpy(char *s1, char *s2); -static char *str_cat(char *s1, char *s2); -static void num_to_str(char *buf, int num); - -static void verb_help(winid_t win); -static void verb_jump(winid_t win); -static void verb_yada(winid_t win); -static void verb_both(winid_t win); -static void verb_clear(winid_t win); -static void verb_page(winid_t win); -static void verb_pageboth(winid_t win); -static void verb_timer(winid_t win); -static void verb_untimer(winid_t win); -static void verb_chars(winid_t win); -static void verb_quit(winid_t win); - -/* The glk_main() function is called by the Glk system; it's the main entry - point for your program. */ -void glk_main(void) -{ - char commandbuf1[256]; /* For mainwin1 */ - char commandbuf2[256]; /* For mainwin2 */ - - /* Open the main windows. */ - mainwin1 = glk_window_open(0, 0, 0, wintype_TextBuffer, 1); - if (!mainwin1) { - /* It's possible that the main window failed to open. There's - nothing we can do without it, so exit. */ - 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 - that. */ - 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, - 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(" split the window vertically, 'c' to close a window,"); - glk_put_string(" and any other key (including special keys) to display"); - 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, - 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(); - - inputpending1 = FALSE; - 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 - 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>"); - /* See above. */ - 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 - pending. We also set commandbuf to point to the - appropriate buffer. Then we leave the event loop. */ - if (mainwin1 && ev.win == mainwin1) { - whichwin = mainwin1; - inputpending1 = FALSE; - cmd = commandbuf1; - doneloop = TRUE; - } - else if (mainwin2 && ev.win == mainwin2) { - whichwin = mainwin2; - inputpending2 = FALSE; - cmd = commandbuf2; - doneloop = TRUE; - } - break; - - case evtype_CharInput: - /* It's a key event, from one of the keywins. We - call a subroutine rather than exiting the - event loop (although I could have done it - 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; - 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 - event loop. */ - draw_statuswin(); - draw_keywins(); - 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++) { - *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_set_window(whichwin); - glk_put_string("Excuse me?\n"); - } - else if (str_eq(cmd, "help")) { - verb_help(whichwin); - } - else if (str_eq(cmd, "yada")) { - verb_yada(whichwin); - } - else if (str_eq(cmd, "both")) { - verb_both(whichwin); - } - else if (str_eq(cmd, "clear")) { - verb_clear(whichwin); - } - else if (str_eq(cmd, "page")) { - verb_page(whichwin); - } - else if (str_eq(cmd, "pageboth")) { - verb_pageboth(whichwin); - } - else if (str_eq(cmd, "timer")) { - verb_timer(whichwin); - } - else if (str_eq(cmd, "untimer")) { - verb_untimer(whichwin); - } - else if (str_eq(cmd, "chars")) { - verb_chars(whichwin); - } - else if (str_eq(cmd, "jump")) { - verb_jump(whichwin); - } - else if (str_eq(cmd, "quit")) { - verb_quit(whichwin); - } - else { - glk_set_window(whichwin); - glk_put_string("I don't understand the command \""); - glk_put_string(cmd); - glk_put_string("\".\n"); - } - - if (whichwin == mainwin1) - already1 = 0; - else if (whichwin == mainwin2) - already2 = 0; - } -} - -static void draw_statuswin(void) -{ - glui32 width, height; - - if (!statuswin) { - /* 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) - width--; - 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 - one created at startup, and any later ones. It finds them all - with glk_window_iterate. */ -static void draw_keywins(void) -{ - winid_t win; - glui32 rock; - glui32 width, height; - - for (win = glk_window_iterate(NULL, &rock); - win; - win = glk_window_iterate(win, &rock)) { - if (rock == KEYWINROCK) { - glk_set_window(win); - glk_window_clear(win); - glk_window_get_size(win, &width, &height); - glk_window_move_cursor(win, 0, 0); - glk_put_char('O'); - glk_window_move_cursor(win, width-1, 0); - glk_put_char('O'); - glk_window_move_cursor(win, 0, height-1); - glk_put_char('O'); - glk_window_move_cursor(win, width-1, height-1); - glk_put_char('O'); - } - } -} - -/* React to character input in a key window. */ -static void perform_key(winid_t win, glui32 key) -{ - glui32 width, height, len; - int ix; - char buf[128], keyname[64]; - - if (key == 'h' || key == 'v') { - winid_t newwin; - glui32 loc; - /* Open a new keywindow. */ - if (key == 'h') - loc = winmethod_Right | winmethod_Proportional; - else - loc = winmethod_Below | winmethod_Proportional; - 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. */ - if (newwin) { - /* Request character input. In this program, only keywins - get char input, so the CharInput events always call - perform_key() -- and so the new window will respond - to keys just as this one does. */ - glk_request_char_event(newwin); - /* We now have to redraw the keywins, because any or all of - them could have changed size when we opened newwin. - glk_window_open() does not generate Arrange events; we - have to do the redrawing manually. */ - draw_keywins(); - } - /* Re-request character input for this window, so that future - keys are accepted. */ - glk_request_char_event(win); - return; - } - else if (key == 'c') { - /* Close this keywindow. */ - glk_window_close(win, NULL); - /* Again, any key windows could have changed size. Also the - status window could have (if this was the last key window). */ - draw_keywins(); - draw_statuswin(); - return; - } - - /* Print a string naming the key that was just hit. */ - - switch (key) { - case ' ': - str_cpy(keyname, "space"); - break; - case keycode_Left: - str_cpy(keyname, "left"); - break; - case keycode_Right: - str_cpy(keyname, "right"); - break; - case keycode_Up: - str_cpy(keyname, "up"); - break; - case keycode_Down: - str_cpy(keyname, "down"); - break; - case keycode_Return: - str_cpy(keyname, "return"); - break; - case keycode_Delete: - str_cpy(keyname, "delete"); - break; - case keycode_Escape: - str_cpy(keyname, "escape"); - break; - case keycode_Tab: - str_cpy(keyname, "tab"); - break; - case keycode_PageUp: - str_cpy(keyname, "page up"); - break; - case keycode_PageDown: - str_cpy(keyname, "page down"); - break; - case keycode_Home: - str_cpy(keyname, "home"); - break; - case keycode_End: - str_cpy(keyname, "end"); - break; - default: - if (key >= keycode_Func1 && key < keycode_Func12) { - str_cpy(keyname, "function key"); - } - else if (key < 32) { - str_cpy(keyname, "ctrl-"); - keyname[5] = '@' + key; - keyname[6] = '\0'; - } - else if (key <= 255) { - keyname[0] = key; - keyname[1] = '\0'; - } - else { - str_cpy(keyname, "unknown key"); - } - 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 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); -} - -/* React to a timer event. This just prints "Tick" in mainwin1, but it - first has to cancel line input if any is pending. */ -static void perform_timer() -{ - event_t ev; - - if (!mainwin1) - return; - - if (inputpending1) { - glk_cancel_line_event(mainwin1, &ev); - if (ev.type == evtype_LineInput) - already1 = ev.val1; - inputpending1 = FALSE; - } - - glk_set_window(mainwin1); - glk_put_string("Tick.\n"); -} - -/* This is a utility function. Given a main window, it finds the - "other" main window (if both actually exist) and cancels line - input in that other window (if input is pending.) It does not - set the output stream to point there, however. If there is only - one main window, this returns 0. */ -static winid_t print_to_otherwin(winid_t win) -{ - winid_t otherwin = NULL; - event_t ev; - - if (win == mainwin1) { - if (mainwin2) { - otherwin = mainwin2; - glk_cancel_line_event(mainwin2, &ev); - if (ev.type == evtype_LineInput) - already2 = ev.val1; - inputpending2 = FALSE; - } - } - else if (win == mainwin2) { - if (mainwin1) { - otherwin = mainwin1; - glk_cancel_line_event(mainwin1, &ev); - if (ev.type == evtype_LineInput) - already1 = ev.val1; - 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"); - glk_put_string("YADA: Print a long paragraph.\n"); - glk_put_string("BOTH: Print a short message in both main windows.\n"); - glk_put_string("CLEAR: Clear one window.\n"); - glk_put_string("PAGE: Print thirty lines, demonstrating paging.\n"); - glk_put_string("PAGEBOTH: Print thirty lines in each window.\n"); - glk_put_string("TIMER: Turn on a timer, which ticks in the upper "); - glk_put_string("main window every three seconds.\n"); - glk_put_string("UNTIMER: Turns off the timer.\n"); - glk_put_string("CHARS: Prints the entire Latin-1 character set.\n"); - glk_put_string("QUIT: Quit and exit.\n"); -} - -static void verb_jump(winid_t win) -{ - glk_set_window(win); - - glk_put_string("You jump on the fruit, spotlessly.\n"); -} - -/* Print some text in both windows. This uses print_to_otherwin() to - find the other window and prepare it for printing. */ -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"); - } -} - -/* Clear a window. */ -static void verb_clear(winid_t win) -{ - glk_window_clear(win); -} - -/* Print thirty lines. */ -static void verb_page(winid_t win) -{ - int ix; - char buf[32]; - - glk_set_window(win); - for (ix=0; ix<30; ix++) { - num_to_str(buf, ix); - glk_put_string(buf); - glk_put_char('\n'); - } -} - -/* 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(). - There's no particular difference; this is just a demonstration. */ -static void verb_pageboth(winid_t win) -{ - int ix; - winid_t otherwin; - strid_t str, otherstr; - char buf[32]; - - str = glk_window_get_stream(win); - otherwin = print_to_otherwin(win); - if (otherwin) - otherstr = glk_window_get_stream(otherwin); - else - otherstr = NULL; - - for (ix=0; ix<30; ix++) { - num_to_str(buf, ix); - str_cat(buf, "\n"); - glk_put_string_stream(str, buf); - if (otherstr) - glk_put_string_stream(otherstr, buf); - } -} - -/* Turn on the timer. The timer prints a tick in mainwin1 every three - seconds. */ -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; -} - -/* Turn off the timer. */ -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; -} - -/* Print every character, or rather try to. */ -static void verb_chars(winid_t win) -{ - int ix; - char buf[16]; - - glk_set_window(win); - - for (ix=0; ix<256; ix++) { - num_to_str(buf, ix); - glk_put_string(buf); - glk_put_string(": "); - glk_put_char(ix); - glk_put_char('\n'); - } -} - -static void verb_yada(winid_t win) -{ - /* 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] = { - "Ga", "Bo", "Wa", "Mu", "Bi", "Fo", "Za", "Mo", "Ra", "Po", - "Ha", "Ni", "Na" - }; - static char *wordlist[NUMWORDS] = { - "figgle", "wob", "shim", "fleb", "moobosh", "fonk", "wabble", - "gazoon", "ting", "floo", "zonk", "loof", "lob", - }; - static int wcount1 = 0; - static int wcount2 = 0; - static int wstep = 1; - 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++; - if (wcount1 >= NUMWORDS) { - wcount1 = 0; - wstep++; - wcount2++; - if (wcount2 >= NUMWORDS-2) { - wcount2 = 0; - 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. */ -} - -/* simple string length test */ -static int str_len(char *s1) -{ - int len; - for (len = 0; *s1; s1++) - len++; - return len; -} - -/* simple string comparison test */ -static int str_eq(char *s1, char *s2) -{ - for (; *s1 && *s2; s1++, s2++) { - if (*s1 != *s2) - return FALSE; - } - - if (*s1 || *s2) - return FALSE; - else - return TRUE; -} - -/* simple string copy */ -static char *str_cpy(char *s1, char *s2) -{ - char *orig = s1; - - for (; *s2; s1++, s2++) - *s1 = *s2; - *s1 = '\0'; - - return orig; -} - -/* simple string concatenate */ -static char *str_cat(char *s1, char *s2) -{ - char *orig = s1; - - while (*s1) - s1++; - for (; *s2; s1++, s2++) - *s1 = *s2; - *s1 = '\0'; - - return orig; -} - -/* simple number printer */ -static void num_to_str(char *buf, int num) -{ - 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++; - num /= 10; - } - for (ix=0; ix