home *** CD-ROM | disk | FTP | other *** search
- /*
- * TEXTWIN.C - Text-windowing system
- * Turbo C 2.0
- *
- * Description: Provides a simple text-menuing interface. Includes pop-down
- * menus, and scrolling windows. To use, set up a main window
- * with the MainWindow() function.
- * eg. MainWindow("Title", 2, "Files", 'f', "Help", 'h');
- *
- * Then set the commands and command-numbers for each menu use
- * the SetMenu function.
- * eg. SetMenu(0, 3, "Open",'o',0, "Close",'c',1, "Quit",'q',2);
- * SetMenu(1, 3, "Help",'h',3, "------------",-1,-1, "About",'a',4);
- *
- * Now just make a call to Choice() and the number it returns
- * will be the command-number of the choice
- * eg. If Help|About is chosen, 4 will be returned.
- *
- * If you want to get the user to select an option from a list
- * of options, make an array of strings with the option
- * descriptions in them (ensure final element is NULL). The
- * element number chosen will be returned (first element = 0)
- * after a call to ScrollChoice()
- * eg. If the array is a, and the maximum string length is l, make the call
- * ScrollChoice("BetterTitle", a, l);
- *
- * To display test inside a box, call DrawBox() with a NULL-
- * terminated array of strings.
- * eg. If the array is a, call
- * DrawBox(a);
- *
- * To display text inside a box, and then wait for a key to be
- * pressed, set up a NULL-terminated array of strings and call
- * the InfoBox() function
- * eg. If the array is a, make the call
- * InfoBox(a);
- *
- * If you want to get input as well as print a box, make a call
- * to DialogBox(), if nothing is entered, a default string is
- * returned
- * eg. DialogBox(a, "C:\") would return "C:\" if nothing was entered.
- *
- *
- * Author: Andrew Scott (Adrenalin Software)
- *
- * Date: 14/3/1993 ver 0.1
- */
-
- #include <conio.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
-
- /* Maximum number of chars in a menu title */
- #define MAXMENUWIDTH 9
- /* Maximum number of chars in a menu command */
- #define MAXCOMMWIDTH 12
- /* Border graphics */
- #define CRNRTL '┌'
- #define CRNRTR '┐'
- #define CRNRBL '└'
- #define CRNRBR '┘'
- #define HORIBAR '─'
- #define VERTBAR '│'
-
- typedef char *string;
-
- struct MenuStruct {
- char n[MAXCOMMWIDTH+1]; /* Item name ("" = no items) */
- int k; /* Key-press selector (lower case) */
- int x; /* Function reference number (-ve = no command) */
- };
- typedef struct MenuStruct *MenuItem;
-
- struct MenuBar {
- char n[MAXMENUWIDTH+1]; /* Menu name ("" = no menus) */
- int k; /* Key-press selector (lower case) */
- MenuItem m; /* Menu items */
- } *Main;
-
-
- #if 0
- string parmlist(string bit, int n)
- {
- string s, t;
- int l;
-
- s = t = (string) malloc(1 + n * (l = strlen(bit)));
- while (n--) {
- strcpy(t, bit);
- t += l;
- }
- return s;
- }
- #endif
-
- void MainWindow(string title, int num, ...)
- /* Post: Screen is set up with a nice title and num menus */
- {
- va_list args;
- string t;
- int i;
- struct MenuBar *c;
-
- c = Main = (struct MenuBar *) malloc(sizeof(struct MenuBar) * (num + 1));
- va_start(args, &num);
- textmode(C80);
- textcolor(CYAN);
- textbackground(BLACK);
- clrscr();
- textbackground(BLUE);
- textcolor(WHITE);
- i = 80 - strlen(title);
- cprintf("%*c%s%*c", i/2, ' ', title, i/2 + i%2, ' ');
- textcolor(YELLOW);
- cprintf(" ");
- for (i = num; i--; c++) {
- t = (va_arg(args, string));
- strcpy(c->n, t);
- cprintf("%-*s", MAXMENUWIDTH, t);
- c->k = (va_arg(args, int));
- c->m = NULL;
- }
- c->n[0] = 0;
- cprintf("%*c", 79 - MAXMENUWIDTH * num, ' ');
- va_end(args);
- }
-
- void SetMenu(int menu, int n, ...)
- /* Post: n commands has been set in menu #menu (0 = 1st) */
- {
- va_list args;
- string t;
- struct MenuBar *c1;
- MenuItem c2;
-
- int i;
-
- for (i = menu, c1 = Main; i-- && c1->n[0] != 0; c1++);
- if (! c1->n[0])
- return; /* error */
- c1->m = c2 = (MenuItem) malloc(sizeof(struct MenuStruct) * (n + 1));
- va_start(args, &n);
- for (; n--; c2++) {
- t = va_arg(args, string);
- strcpy(c2->n, t);
- c2->k = va_arg(args, int);
- c2->x = va_arg(args, int);
- }
- c2->n[0] = 0;
- }
-
- int _Menulength_; /* ignore this unstructured global variable ;) */
-
- void PrintMenu(MenuItem m, int x)
- /* Post: The menu which is pointed to by m is printed at column x */
- {
- int i;
- char t[MAXCOMMWIDTH + 3];
-
- i = MAXCOMMWIDTH+2;
- t[i] = 0;
- while (i--)
- t[i] = HORIBAR;
- textcolor(YELLOW);
- textbackground(BLUE);
- gotoxy(x, 3);
- cprintf("%c%s%c", CRNRTL, t, CRNRTR);
- _Menulength_ = 2;
- i = 4;
- while (m->n[0]) {
- _Menulength_++;
- gotoxy(x, i++);
- cprintf("%c %-*s %c", VERTBAR, MAXCOMMWIDTH, (m++)->n, VERTBAR);
- }
- gotoxy(x, i);
- cprintf("%c%s%c", CRNRBL, t, CRNRBR);
- }
-
- void ClearMenu(int x)
- /* Post: The last menu printed at column x is now gone */
- {
- int i = 3;
-
- textcolor(CYAN);
- textbackground(BLACK);
- while (_Menulength_--) {
- gotoxy(x, i++);
- cprintf("%*c", MAXCOMMWIDTH + 4, ' ');
- }
- }
-
- void PrintComm(MenuItem m, int x, int y)
- /* Post: Item *m is highlighted at column x, position y */
- {
- gotoxy(x+1, y+4);
- textcolor(MAGENTA);
- textbackground(BLACK);
- cprintf(" %-*s ", MAXCOMMWIDTH, m->n);
- }
-
- void ClearComm(MenuItem m, int x, int y)
- /* Post: Item *m is normalized at column x, position y */
- {
- gotoxy(x+1, y+4);
- textcolor(YELLOW);
- textbackground(BLUE);
- cprintf(" %-*s ", MAXCOMMWIDTH, m->n);
- }
-
- void PrintBar(string s, int w, int y)
- /* Post: String s (width w) is highlighted in the text window on line y */
- {
- gotoxy(1, y+1);
- textcolor(WHITE);
- textbackground(BLACK);
- cprintf(" %-*s ", w, s);
- }
-
- void ClearBar(string s, int w, int y)
- /* Post: String s (width w) is normalized in the text window on line y */
- {
- gotoxy(1, y+1);
- textcolor(BLACK);
- textbackground(CYAN);
- cprintf(" %-*s ", w, s);
- }
-
- void Beep()
- /* Post: Speaker has made a beep */
- {
- printf("%c", 7);
- }
-
- int Choice()
- /*
- * Returns: a function reference number corresponding to a chosen command,
- * but returns -1 on an error.
- */
- {
- int ch;
- struct MenuBar *c;
- MenuItem p, q;
- int i, fx = -1, y;
-
- textcolor(CYAN);
- textbackground(BLACK);
- gotoxy(1, 25);
- do {
- cprintf("\rPress the letter of the menu you wish to select.");
- ch = tolower(getch());
- for (c = Main, i = 0; c->n[0] && c->k != ch; c++, i++);
- i = 2 + MAXMENUWIDTH * i;
- if (c->n[0] != 0)
- do {
- cprintf("\rPress a letter, or use cursor keys and <RETURN> to select a command.");
- gotoxy(i, 2);
- textbackground(BLUE);
- textcolor(LIGHTRED);
- cprintf("%-*s", MAXMENUWIDTH, c->n);
- PrintMenu(p = c->m, i);
- PrintComm(p, i, y = 0);
- do {
- ch = tolower(getch());
- if (!ch) {
- ch = -getch();
- if (ch==-72) /* up-arrow */
- if (!y)
- Beep();
- else {
- ClearComm(p--, i, y--);
- PrintComm(p, i, y);
- }
- else if (ch==-80) /* down-arrow */
- if (! (p+1)->n[0])
- Beep();
- else {
- ClearComm(p++, i, y++);
- PrintComm(p, i, y);
- }
- } else {
- for (q = c->m; q->n[0] && q->k != ch; q++);
- if (q->n[0])
- fx = q->x;
- }
- } while ((ch==-72 || ch==-80) && fx < 0);
- if (ch==13 && fx < 0)
- fx = p->x;
- ClearMenu(i);
- gotoxy(i, 2);
- textbackground(BLUE);
- textcolor(YELLOW);
- cprintf("%-*s", MAXMENUWIDTH, c->n);
- textcolor(CYAN);
- textbackground(BLACK);
- gotoxy(1, 25);
- cprintf("%52c", ' ');
- if (ch==-75)
- if (i==2)
- Beep();
- else {
- i -= MAXMENUWIDTH;
- c--;
- }
- else if (ch==-77)
- if (! (c+1)->n[0])
- Beep();
- else {
- i += MAXMENUWIDTH;
- c++;
- }
- } while (ch != 27 && fx < 0);
- clreol();
- } while (fx < 0);
- return fx;
- }
-
- void ClearWin()
- /* Post: Area below command and title bars is clear */
- {
- textcolor(CYAN);
- textbackground(BLACK);
- window(1, 3, 80, 25);
- clrscr();
- window(1, 1, 80, 25);
- }
-
- int ScrollChoice(string title, string *sp, int w)
- /*
- * Returns: The offset of the string from s which is chosen, -1 on none
- * s points to the start of a list of strings, max length w, NULL term.
- */
- {
- string s, t, *srt, *end;
- int l, p, cur, ch, x = -1;
-
- if (strlen(title) > w)
- w = strlen(title);
- textcolor(CYAN);
- textbackground(BLACK);
- gotoxy(1, 25);
- cprintf("Use cursor keys and <RETURN> to make a selection.");
- s = t = (string) malloc(w + 3);
- for (p = w+2; p--; *(t++) = HORIBAR);
- *t = 0;
- gotoxy(5,3);
- textcolor(BLACK);
- textbackground(CYAN);
- cprintf("%c%s%c", CRNRTL, s, CRNRTR);
- gotoxy(6 + (w - strlen(title))/2, 3);
- cprintf(" %s ", title);
- srt = end = sp;
- for (end = sp, l = 0; *end!=NULL && l<20; l++) {
- gotoxy(5, l+4);
- cprintf("%c %-*s %c", VERTBAR, w, *(end++), VERTBAR);
- }
- end--;
- gotoxy(5, l+4);
- cprintf("%c%s%c", CRNRBL, s, CRNRBR);
- free(s);
- window(6, 4, 8+w, l+3);
- PrintBar(*srt, w, p = 0);
- cur = 0;
- x = -1;
- do {
- ch = tolower(getch());
- if (!ch) {
- ch = -getch();
- if (ch==-72)
- if (!cur)
- Beep();
- else if (p) {
- ClearBar(*(srt+p), w, p);
- p--;
- PrintBar(*(srt+p), w, p);
- cur--;
- } else {
- ClearBar(*(srt--), w, 0);
- gotoxy(1, 1);
- insline();
- gotoxy(w+3, 1);
- cprintf("%c", VERTBAR);
- PrintBar(*srt, w, 0);
- end--;
- cur--;
- }
- else if (ch==-80)
- if (p==l-1 && *(end+1)==NULL)
- Beep();
- else if (p < l-1) {
- ClearBar(*(srt+p), w, p);
- p++;
- cur++;
- PrintBar(*(srt+p), w, p);
- } else {
- ClearBar(*end, w, p);
- end++;
- gotoxy(w+3, l);
- cprintf("%c", VERTBAR); /* argh.. cant print at final corner */
- cur++;
- PrintBar(*end, w, p);
- srt++;
- }
- } else if (ch==13)
- x = cur;
- } while (x < 0 && ch != 27);
- ClearWin();
- return x;
- }
-
- void PrintBox(string *sp, int *x1, int *y1, int *w1)
- /*
- * Post: The NULL-terminated array of strings pointed to by sp is printed,
- * and x1, y1 are set to be the co-ordinates of the bottom-left corner,
- * w1 is set to be the width of the inside of the box.
- */
- {
- int w, x, i, j;
- string s, t, *c;
-
- if (*sp==NULL)
- return;
- c = sp;
- for (w = strlen(*(c++)), i = 1; *c!=NULL; c++, i++)
- if (w < (x = strlen(*c)))
- w = x;
- *w1 = w + 2;
- *x1 = 1 + (x = (76 - w)/2);
- i = 3 + (21 - i)/2;
- s = t = (string) malloc(w+3);
- for (j = w+2; j--; *(t++) = HORIBAR);
- *t = 0;
- textcolor(BLACK);
- textbackground(CYAN);
- gotoxy(x, i++);
- cprintf("%c%s%c", CRNRTL, s, CRNRTR);
- for (c = sp; *c!=NULL; c++) {
- gotoxy(x, i++);
- cprintf("%c %-*s %c", VERTBAR, w, *c, VERTBAR);
- }
- *y1 = i-1;
- gotoxy(x, i);
- cprintf("%c%s%c", CRNRBL, s, CRNRBR);
- free(s);
- }
-
- void DrawBox(string *sp)
- /* Post: The NULL-terminated array of strings pointed to by sp is printed */
- {
- int i;
-
- PrintBox(sp, &i, &i, &i);
- }
-
- char InfoBox(string *sp)
- /*
- * Returns: The key pressed after the NULL-terminated array of strings
- * pointed to by sp is printed.
- */
- {
- int k;
-
- DrawBox(sp);
- textcolor(CYAN);
- textbackground(BLACK);
- gotoxy(1, 25);
- cprintf("Please press a key.");
- k = getch();
- ClearWin();
- return k;
- }
-
- string DialogBox(string *sp, string def)
- /* Pre: def != NULL */
- /*
- * Returns: The string entered (or def if none entered), after printing
- * box filled with NULL-terminated strings sp.
- */
- {
- int x, y, w, ch, i=0;
- string s;
-
- PrintBox(sp, &x, &y, &w);
- s = (string) malloc(w+1);
- strcpy(s, def);
- textcolor(CYAN);
- textbackground(BLACK);
- gotoxy(1, 25);
- cprintf("Enter text, and when you are finished, press <RETURN>.");
- textcolor(WHITE);
- gotoxy(x, y);
- cprintf("%-*s", w, s);
- window(x, y, x+w-1, y);
- gotoxy(1, 1);
- x = strlen(s);
- do {
- if (!(ch = getch()))
- ch = -getch();
- if (ch==8 || ch==127)
- if (!i)
- Beep();
- else {
- cprintf("\b");
- clreol();
- x = --i;
- }
- else if (ch==-75)
- if (!i)
- Beep();
- else {
- cprintf("\b");
- i--;
- }
- else if (ch==-77)
- if (i==x)
- Beep();
- else {
- cprintf("%c", s[i]);
- i++;
- }
- else if (ch!=13 && ch!=27)
- if (i==w-1)
- Beep();
- else {
- cprintf("%c", ch);
- if (i==x)
- x++;
- s[i++] = ch;
- }
- } while (ch!=13 && ch!=27);
- s[i] = 0;
- if (ch==27) {
- free(s);
- strcpy(s = (string) malloc(strlen(def)+1), def);
- }
- ClearWin();
- return s;
- }
-
- /*
- * This main function is for testing the basics of these routines.
- * Leave it commented out when creating object files.
- *
- main()
- {
- string scrolly[] = {
- "First one",
- "Second option",
- "3rd",
- "4th",
- "Fifth",
- "This could go on for AGES",
- "Why not stop soon?",
- "Ok",
- "How about the next one",
- "Done",
- "Nope",
- "Here's another few..",
- "Un",
- "Deux",
- "Trois",
- "Quatre",
- "When should I stop?",
- "Not yet obviously.",
- "Cinq",
- "Six",
- "Sept",
- "I think that's enough",
- "Well maybe one more.",
- NULL
- };
- string diagbox[] = {
- "Please enter some gibberish",
- "below at the prompt please.",
- "It WONT check your spelling.",
- "",
- "",
- NULL
- };
- string s;
-
- MainWindow("Big Huge Title", 3, "Ace", 'a', "Bee", 'b', "seaCide", 'c');
- SetMenu(0, 3, "First", 'f', 1, "------------", -1, -1, "Second", 's', 2);
- SetMenu(1, 1, "Spelling", 's', 3);
- SetMenu(2, 2, "I'd like", 'i', 4, "To be beside", 't', 5);
- while (1)
- switch (Choice()) {
- case 1:
- ScrollChoice("Window Name", scrolly, 25);
- break;
- case 3:
- s = DialogBox(diagbox, "sample");
- free(s);
- break;
- case 5:
- exit(0);
- }
- }
- * Ok.. this ends the commented out part
- */