File: programming/cocoa/MacScare-Source.zip/MacScare-Source/multiwin.c


#include "glk.h"
 
/* multiwin.c: Sample program for Glk API, version 0.5.
    Designed by Andrew Plotkin <erkyrath@eblong.com>
    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. *//* 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.) *//* 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. *//* There's a three-second timer which can be on or off. *//* Forward declarations *//* The glk_main() function is called by the Glk system; it's the main entry
    point for your program. *//* For mainwin1 *//* For mainwin2 */
 
    /* Open the main windows. *//* It's possible that the main window failed to open. There's
            nothing we can do without it, so exit. *//* 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. *//* And a third window, a second story window below the main one. *//* 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.) */"Multiwin\nAn Interactive Sample Glk Program\n""By Andrew Plotkin.\nRelease 3.\n""Type \"help\" for a list of commands.\n""Note that the upper left-hand window accepts character"" input. Hit 'h' to split the window horizontally, 'v' to"" split the window vertically, 'c' to close a window,"" and any other key (including special keys) to display"" key codes. All new windows accept these same keys as"" well.\n\n""This bottom window accepts normal line input.\n"/* For fun, let's open a fourth window now, splitting the status
            window. *//* Draw the key window now, since we don't draw it every input (as
        we do the status window. *//* 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. */"\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. */"\n>");
            /* See above. *//* Grab an event. *//* 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. *//* 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.) *//* 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. *//* Windows have changed size, so we have to redraw the
                        status window and key window. But we stay in the
                        event loop. *//* It was a timer event. *//* 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. *//* Then trim whitespace before and after. */' '' '; cx--) { };
        *(cx+1) = '\0';
        
        /* cmd now points to a nice null-terminated string. We'll do the
            simplest possible parsing. */"""Excuse me?\n""help""yada""both""clear""page""pageboth""timer""untimer""chars""jump""quit""I don't understand the command \"""\".\n"/* It is possible that the window was not successfully 
            created. If that's the case, don't try to draw it. *//* Draw a decorative compass rose in the center. */"\\|/""-*-""/|\\");
    
}
 
/* 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. */'O''O''O''O');
        }
    }
}
 
/* React to character input in a key window. */'h' || key == 'v') {
        winid_t newwin;
        glui32 loc;
        /* Open a new keywindow. */'h'/* Since the new window has rock value KEYWINROCK, the
            draw_keywins() routine will redraw it. *//* 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. *//* 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. */'c') {
        /* Close this keywindow. *//* Again, any key windows could have changed size. Also the
            status window could have (if this was the last key window). *//* Print a string naming the key that was just hit. */' ':
            str_cpy(keyname, "space""left""right""up""down""return""delete""escape""tab""page up""page down""home""end""function key""ctrl-");
                keyname[5] = '@' + key;
                keyname[6] = '\0''\0'"unknown key""Key: ");
    str_cat(buf, keyname);
    
    len = str_len(buf);
    
    /* Print the string centered in this window. */' '/* Re-request character input for this window, so that future
        keys are accepted. *//* React to a timer event. This just prints "Tick" in mainwin1, but it
    first has to cancel line input if any is pending. */"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. */"This model only understands the following commands:\n""HELP: Display this list.\n""JUMP: Print a short message.\n""YADA: Print a long paragraph.\n""BOTH: Print a short message in both main windows.\n""CLEAR: Clear one window.\n""PAGE: Print thirty lines, demonstrating paging.\n""PAGEBOTH: Print thirty lines in each window.\n""TIMER: Turn on a timer, which ticks in the upper ""main window every three seconds.\n""UNTIMER: Turns off the timer.\n""CHARS: Prints the entire Latin-1 character set.\n""QUIT: Quit and exit.\n""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. */"Something happens in this window.\n""Something happens in the other window.\n");
    }
}
 
/* Clear a window. *//* Print thirty lines. */'\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. */"\n"/* Turn on the timer. The timer prints a tick in mainwin1 every three
    seconds. */"The timer is already running.\n""Your Glk library does not support timer events.\n""A timer starts running in the upper window.\n"/* Every three seconds. *//* Turn off the timer. */"The timer is not currently running.\n""The timer stops running.\n"/* Print every character, or rather try to. */": "'\n'/* 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)
"Ga", "Bo", "Wa", "Mu", "Bi", "Fo", "Za", "Mo", "Ra", "Po",
            "Ha", "Ni", "Na""figgle", "wob", "shim", "fleb", "moobosh", "fonk", "wabble",
            "gazoon", "ting", "floo", "zonk", "loof", "lob"" ""."'\n'"Thanks for playing.\n"/* glk_exit() actually stops the process; it does not return. */
}
 
/* simple string length test *//* simple string comparison test *//* simple string copy */'\0'/* simple string concatenate */'\0'/* simple number printer */"0"'-''0''\0';
}

This code uses the PclZip Zip File reading code, which is subject to the GNU LGPL. It also uses the GeSHi syntax highlighter, subject to the GPL. Ask if you want this for your own web site, it's free.