home *** CD-ROM | disk | FTP | other *** search
- From: lee@sq.sq.com (Liam R. E. Quin)
- Newsgroups: alt.sources
- Subject: lq-text Full Text Retrieval Database Part 09/13
- Message-ID: <1991Mar4.020855.16769@sq.sq.com>
- Date: 4 Mar 91 02:08:55 GMT
-
- : cut here --- cut here --
- : To unbundle, sh this file
- #! /bin/sh
- : part 09
- echo x - lq-text/src/menu/menu.c 1>&2
- sed 's/^X//' >lq-text/src/menu/menu.c <<'@@@End of lq-text/src/menu/menu.c'
- X/* menu.c -- curses based windowing interface
- X * Liam Quin, July 1989
- X *
- X * $Id: menu.c,v 1.3 90/10/13 03:06:36 lee Rel1-10 $
- X *
- X * $Log: menu.c,v $
- X * Revision 1.3 90/10/13 03:06:36 lee
- X * After Sabre.
- X *
- X * Revision 1.2 90/10/04 16:28:19 lee
- X * SysV compat improved.
- X *
- X * Revision 1.1 90/08/29 21:50:42 lee
- X * Initial revision
- X *
- X * Revision 2.1 89/08/07 13:50:09 lee
- X * First fully working (V.3.2 only) release;
- X * this is the baseline for future development.
- X *
- X * Revision 1.4 89/08/04 17:58:31 lee
- X * Fully working with Basic Functionality.
- X * Scrolling menubar, scrolling menus, moveable Info windows.
- X *
- X * Revision 1.3 89/08/02 17:12:21 lee
- X * gernally working.
- X * You can scroll up/down in menus.
- X *
- X * Revision 1.2 89/07/28 18:20:17 lee
- X * Pull-down menus now scroll if the items don't all fit on the screen.
- X * The info-boxes pop up nearer to the highlighted item.
- X * Help on menu-bar items.
- X * In infoshow(), arrow keys return, so you can move from one item to
- X * another and have the info boxes displayed foe each.
- X *
- X * Revision 1.1 89/07/27 11:38:23 lee
- X * Initial revision
- X *
- X * Revision 1.1 89/07/24 18:34:43 lee
- X * Initial revision
- X *
- X *
- X */
- X
- X#ifndef lint
- Xstatic char rcsid[] = "@(#) $Id: menu.c,v 1.3 90/10/13 03:06:36 lee Rel1-10 $";
- X#endif
- X
- X#ifdef ultrix
- X# include <cursesX.h>
- X#else
- X# include <curses.h>
- X#endif
- X#include <malloc.h>
- X
- X#ifndef A_STANDOUT
- X# include "oldcurses.h"
- X#endif
- X
- X#include "menu.h"
- X#include "internal.h"
- X#include "error.h"
- X
- Xvoid SetStringBoxSize();
- X
- X/* Some Shorthand */
- X#define BL (MENUTOP - 1)
- X/* VSO is Vertical Scroll Offset... */
- X#define VSO (Menu->TopLineOnScreen)
- X
- X
- X/* Appearance of menus:
- X * Each menu is boxed with the terminal line drawing characters. It will
- X * use '|' if you don't have VLINE; ACS_SSBS looks like the upper-case T
- X * that will join the HLINE of the Menu Line to the menu box itself.
- X * See /usr/include/curses.h for an explanation of these names. On pre-
- X * System V, curses often uses + - and | to draw lines, which is ugly but
- X * doeas at least work. It might be possible to define variables with
- X * the appropriate names (ACS_VLINE, etc), and to put appropriate things
- X * into termcap. Uniplex used to do this, for example.
- X *
- X * If not compiled with -DSAVEMENULINE, to save a line on the screen,
- X * the first line of each menu over-writes the Menu line, so you get:
- X * File Edit Method Position Adults Children Animals
- X * -------------------------------------+ Daniel +-----------------------
- X * | Simon |
- X * | Lorella |
- X * | Carol |
- X * +---------+
- X * Otherwise, you get this:
- X * File Edit Method Position Adults Children Animals
- X * -------------------------------------+---------+-----------------------
- X * | Daniel |
- X * | Simon |
- X * | Lorella |
- X * | Carol |
- X * +---------+
- X * which might look neater, but uses an extra line on the screen.
- X * It saves the menu line on each redraw, hence SAVEMENULINE.
- X *
- X * Most of this is wired into the Show* routines -- ShowMenuBar() and
- X * ShowMenu().
- X */
- X
- Xstatic int DisplayedMenu = 0;
- Xstatic int NextMenuId = 1;
- X
- Xt_Menu *
- XNewMenu(Name)
- X char *Name;
- X{
- X static int MCount = 0;
- X
- X t_Menu *M = (t_Menu *) malloc(sizeof(t_Menu));
- X
- X if (!M) {
- X error(ERR_FATAL, "Not enough memory for new menu");
- X }
- X M->MenuStyle = 0; /* default */
- X M->TopLineOnScreen = 0;
- X M->Width = -1; /*i.e. not calculated yet */
- X M->NameLength = strlen(Name);
- X M->Name = malloc(M->NameLength + 1);
- X if (!M->Name) {
- X error(ERR_FATAL, "Not enough memory for new menu name");
- X }
- X (void) strcpy(M->Name, Name);
- X M->SelectedLine = 0;
- X M->MenuId = MCount++;
- X
- X return M;
- X}
- X
- XShowMenuBar(MenuBar)
- X t_MenuBar *MenuBar;
- X{
- X /* draw a menu bar... */
- X int barpos = 0;
- X int i;
- X int SelectedLength;
- X int EndOfMenu = 0;
- X
- X /* Clear the top two lines. */
- X (void) wmove(stdscr, 0, 0);
- X (void) wclrtoeol(stdscr);
- X (void) wmove(stdscr, 1, 0);
- X (void) wclrtoeol(stdscr);
- X /* draw the menu line */
- X for (i = 0; i < COLS - 1; i++) {
- X (void) mvwaddch(stdscr, 1, i, (chtype) ACS_HLINE);
- X }
- X
- X /* On really slow terminals it might be worth doing a refresh()
- X * at this point, so the clear can happen at the same time as we
- X * are working out the size of the menu bar, etc.
- X */
- X
- X#define HSO (MenuBar->ScrollOffset) /* Horiz. scroll offset */
- X
- X /** Horizontal scrolling of long menus... **/
- X
- X /* Check for sanity! */
- X if (MenuBar->ScrollOffset < 0) {
- X MenuBar->ScrollOffset = 0;
- X }
- X
- X /* Find where to start displaying...
- X * keep adding the menu widths until the selected menu is on screen
- X */
- X
- X /* First, work out the widths. It might be worth pre-computing
- X * these strlen()s....
- X */
- X for (i = 0; i < MenuBar->HowManyMenus; i++) {
- X barpos = (EndOfMenu += 2);
- X MenuBar->Menus[i]->PositionInBar = barpos;
- X if (MenuBar->Menus[i]->NameLength <= 0) {
- X MenuBar->Menus[i]->NameLength = strlen(MenuBar->Menus[i]->Name);
- X }
- X EndOfMenu += MenuBar->Menus[i]->NameLength;
- X }
- X /* Now, we can work out how to get SelectedMenu on screen! */
- X /* First, check we're in range: */
- X if (MenuBar->SelectedMenu == 0) {
- X MenuBar->ScrollOffset = 0;
- X }
- X if (MenuBar->ScrollOffset > EndOfMenu) {
- X MenuBar->ScrollOffset = EndOfMenu;
- X }
- X /* Now, check that SelectedMenu and scrolloffset both fit on the screen
- X */
- X barpos = MenuBar->Menus[MenuBar->SelectedMenu]->PositionInBar;
- X if (MenuBar->ScrollOffset > barpos) {
- X MenuBar->ScrollOffset = barpos - 2;
- X }
- X /* 2 9 20 28 ........... barpos = 28ish
- X * File |<Implement Severity *Duration* Location |
- X *|<--->|ScrollOffset ............. MenuBar->ScrollOffset = 5ish
- X */
- X /* The +6 is
- X * 2 for the extreme left
- X * 2 for the extreme righht
- X * 2 spare, so you can see the menu
- X */
- X SelectedLength = MenuBar->Menus[MenuBar->SelectedMenu]->NameLength;
- X
- X if (barpos - MenuBar->ScrollOffset >= COLS - SelectedLength) {
- X /* it's off the right-hand edge of the screen. The +2
- X * is 1 for a space at the end of the name, leaving room for
- X * a '>' if the bar continues, and one for a space to leave room
- X * for the right edge of the menu bar if it gets pulled down. */
- X MenuBar->ScrollOffset = barpos - (COLS - SelectedLength - 2);
- X }
- X /* Horizontal scrolling of long menus... */
- X if (MenuBar->ScrollOffset < 0) {
- X MenuBar->ScrollOffset = 0;
- X }
- X
- X /* Now the menu bar itself */
- X
- X EndOfMenu = barpos = 0;
- X
- X for (i = 0; i < MenuBar->HowManyMenus; i++) {
- X register char *q;
- X
- X /* leave 2 spaces before each menu so the box lines up
- X * when it's selected.
- X */
- X EndOfMenu += 2;
- X
- X /* Draw the spaces -- EndOfMenu represents the end of the
- X * menubar, in characters, ignoring HSO --- so, it can be
- X * bigger than COLS.
- X */
- X while (barpos < EndOfMenu) {
- X if (barpos >= HSO && barpos < HSO + COLS) {
- X (void) mvwaddch(stdscr, 0, barpos - HSO, (chtype) ' ');
- X }
- X ++barpos;
- X }
- X
- X /* This is really for ShowMenu() */
- X MenuBar->Menus[i]->PositionInBar = barpos - 2 - HSO;
- X
- X
- X if (i == MenuBar->SelectedMenu) {
- X (void) attrset(A_STANDOUT);
- X }
- X
- X for (q = MenuBar->Menus[i]->Name; *q; q++) {
- X /* Only write characters onto the screen in the range
- X * HSO ... HSO + COLS
- X */
- X if (barpos >= HSO && barpos < HSO + COLS) {
- X (void) mvwaddch(stdscr, 0, barpos - HSO, (chtype) *q);
- X }
- X barpos++;
- X }
- X
- X if (i == MenuBar->SelectedMenu) {
- X (void) attrset(0);
- X }
- X
- X if (barpos > COLS + HSO) {
- X break; /* we can give up now! */
- X }
- X
- X EndOfMenu = barpos;
- X }
- X
- X if (barpos == 0) {
- X error(ERR_FATAL, "UseMenuBar: The Menus must have names");
- X }
- X
- X if (MenuBar->ScrollOffset > 0) {
- X (void) mvwaddch(stdscr, 0, 0, ACS_LARROW); /* left arrow */
- X }
- X
- X if (i < MenuBar->HowManyMenus) {
- X /* not all the menuse were shown */
- X (void) mvwaddch(stdscr, 0, COLS - 1, ACS_RARROW); /* right arrow */
- X }
- X}
- X
- Xint
- XUseMenuBar(MenuBar)
- X t_MenuBar *MenuBar;
- X{
- X int SelectedChar;
- X extern int MenuUsed;
- X int InfoBoxOnScreen = 0;
- X
- X MenuBar->ScrollOffset = 0;
- X MenuBar->SelectedMenu = 0;
- X
- X do {
- X int mval;
- X int InMenu;
- X
- X InMenu = 0;
- X
- X ShowMenuBar(MenuBar);
- X (void) refresh();
- X SelectedChar = getch();
- X
- X switch (SelectedChar) {
- X case 'q':
- X case 'f':
- X case 'Q':
- X case 'F':
- X return -2;
- Xinfo_key:
- X case KEY_HELP:
- X case '?':
- X case 'x': /* "eXplain" */
- X case 'X': /* "eXplain" */
- X case 'i': /* "info" */
- X case 'I': /* "Info" */
- X {
- X char *p = MenuBar->Menus[MenuBar->SelectedMenu]->Description;
- X int tlx = MenuBar->Menus[MenuBar->SelectedMenu]->PositionInBar;
- X tlx += 4; /* a little to the right.. */
- X if (!p) {
- X p = "No information available about this menu.";
- X }
- X SelectedChar = ShowInfo(p, (WINDOW *) 0, tlx, 2);
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X InfoBoxOnScreen = (SelectedChar != ' ');
- X if (SelectedChar == 0 || SelectedChar == ' ') {
- X continue;
- X }
- X break;
- X }
- X }
- X /* The character was changed if ShowInfo was called...
- X * The next switch() deals with selecting a menu, and also
- X * canonicalises the input for the subsequent switch().
- X */
- X switch (SelectedChar) {
- X case ' ':
- X /* ShowInfo() returns ' 'to disable the info box. */
- X if (InfoBoxOnScreen) {
- X InfoBoxOnScreen = 0;
- X break;
- X }
- X case '\r':
- X case '\n':
- X case 'j':
- X case KEY_DOWN:
- Xfire_menu:
- X if (InfoBoxOnScreen) {
- X InfoBoxOnScreen = 0;
- X }
- X InMenu = 1;
- X mval = UseMenu(MenuBar->Menus[MenuBar->SelectedMenu]);
- X /* clear(); */
- X if (mval > MenuBar->Menus[MenuBar->SelectedMenu]->HowManyItems ||
- X mval < 0) {
- X SelectedChar = mval;
- X if (mval == -2) {
- X SelectedChar = '\004';
- X continue;
- X }
- X } else {
- X /* If we're supposed to print the final selection on
- X * exit, we need to know which menu was selected ---
- X * see the end of the example main().
- X */
- X MenuUsed = MenuBar->SelectedMenu;
- X
- X if (mval >= 0 && MenuBar->Menus[MenuUsed]->Items[mval].Function != 0) {
- X return (* MenuBar->Menus[MenuUsed]->Items[mval].Function)(MenuBar->Menus[MenuUsed], mval);
- X } else {
- X /* No function to call */
- X return mval;
- X }
- X }
- X break;
- X case 'h':
- X SelectedChar = KEY_LEFT;
- X break;
- X case 'l': /* lower case ell */
- X SelectedChar = KEY_RIGHT;
- X break;
- X }
- X /* The submenu might have been left with KEY_LEFT (say), so
- X * we check again here.
- X */
- X switch (SelectedChar) {
- X case KEY_HOME:
- X MenuBar->ScrollOffset = 0;
- X MenuBar->SelectedMenu = 0;
- X break;
- X case '$':
- X MenuBar->SelectedMenu = MenuBar->HowManyMenus - 1;
- X break;
- X case KEY_LEFT:
- X if (MenuBar->SelectedMenu > 0) {
- X (MenuBar->SelectedMenu)--;
- X ShowMenuBar(MenuBar);
- X } else {
- X (void) beep();
- X }
- X break;
- X case KEY_RIGHT:
- X if (MenuBar->SelectedMenu + 1 < MenuBar->HowManyMenus) {
- X MenuBar->SelectedMenu++;
- X ShowMenuBar(MenuBar);
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'R' ^ 64: /* control-R */
- X (void) clearok(stdscr, TRUE);
- X (void) refresh();
- X break;
- X case ' ':
- X case '\004': /* used internally */
- X break;
- X default:
- X (void) beep();
- X }
- X if (InfoBoxOnScreen) {
- X goto info_key; /* sorry */
- X }
- X if (InMenu) {
- X /* clear(); */
- X ShowMenuBar(MenuBar);
- X (void) refresh();
- X goto fire_menu;
- X }
- X } while (SelectedChar != EOF && SelectedChar != 'q');
- X /*NOTREACHED*/
- X error(ERR_FATAL|ERR_INTERNAL, "/*NOTREACHED*/ in UseMenuBar()");
- X /*NOTREACHED*/
- X return -1;
- X}
- X
- X/* UseMenu() -- display a menu, allow the user to select from it,
- X * then undisplay it and redraw the screen
- X */
- Xint
- XUseMenu(Menu)
- X t_Menu *Menu;
- X{
- X WINDOW *MenuWin;
- X int tlx, bly; /* top left x/bot. right y of menu box */
- X static int InfoBoxOnScreen = 0;
- X
- X if (InfoBoxOnScreen) {
- X InfoBoxOnScreen++; /* force the box to be redrawn */
- X }
- X /* Ensure that the menu has a MenuId --
- X * This is the only module which knows about MenuId...
- X */
- X if (Menu->MenuId <= 0) { /* a new menu */
- X Menu->MenuId = NextMenuId++;
- X }
- X /* If the menu is not currently displayed */
- X if (DisplayedMenu <= 0) {
- X DisplayedMenu = -1;
- X }
- X if (Menu->SelectedLine < 0) {
- X Menu->SelectedLine = 0;
- X Menu->TopLineOnScreen = 0;
- X }
- X tlx = Menu->PositionInBar;
- X if ((bly = Menu->HowManyItems + 2) > LINES - 2) {
- X /* -2 -- one for the menu bar, one because top line is 0 */
- X bly = LINES - 2;
- X }
- X
- X /* Ensure that the width has been calculated */
- X if (Menu->Width <= 0) {
- X (void) FindMenuWidth(Menu);
- X }
- X
- X /* We leave 1 space either side, + 1 for the box */
- X if ((MenuWin = newwin(bly, Menu->Width + 4, 1, tlx)) == (WINDOW *) 0) {
- X (void) beep();
- X error(ERR_FATAL|ERR_INTERNAL, "No more memory");
- X }
- X
- X /* spl6(); */
- X DisplayedMenu = Menu->MenuId;
- X /* spl0(); */
- X
- X for (;;) {
- X int ch;
- X
- X ShowMenu(Menu, MenuWin);
- X (void) wrefresh(MenuWin);
- X
- X ch = (InfoBoxOnScreen > 1) ? KEY_HELP : getch();
- X
- X if (InfoBoxOnScreen > 1) InfoBoxOnScreen = 1;
- X
- X switch (ch) {
- X char *p;
- X
- X case 'q':
- X case 'Q': /* return immediately */
- X case 'f':
- X case 'F': /* Finish */
- X InfoBoxOnScreen = 0;
- X (void) delwin(MenuWin);
- X (void) touchwin(stdscr);
- X return -2;
- X case '?': /* "huhn?" */
- X case 'x': /* "eXplain" */
- X case 'X': /* "eXplain" */
- X case 'i': /* "info" */
- X case 'I': /* "info" */
- X case KEY_HELP:
- Xkey_info:
- X p = Menu->Items[Menu->SelectedLine].Description;
- X
- X if (!p) {
- X p = "No information available for this selection.";
- X }
- X
- X ch = ShowInfo(p, MenuWin, tlx + 4, Menu->SelectedLine + 3 - VSO);
- X
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X (void) touchwin(MenuWin);
- X (void) wrefresh(MenuWin);
- X /* ShowInfo returns SPACE if the user wanted to get
- X * rid of the box; otherwise, it returns the appropriate
- X * key.
- X * The box went away anyway, but we might put another
- X * one there.
- X */
- X InfoBoxOnScreen = (ch != ' ');
- X
- X if (ch == 0 || ch == ' ') continue;
- X break;
- X }
- X
- X /* So either we are looking at the original character,
- X * or the user pressed the Info key...
- X */
- X
- X switch (ch) {
- X case ' ':
- X case '\r':
- X case '\n':
- X (void) delwin(MenuWin);
- X (void) touchwin(stdscr);
- X return Menu->SelectedLine;
- X case KEY_HOME:
- X if (Menu->SelectedLine > 0) {
- X Menu->SelectedLine = 0;
- X if (InfoBoxOnScreen) {
- X ShowMenu(Menu, MenuWin);
- X (void) wrefresh(MenuWin);
- X goto key_info; /* sorry */
- X }
- X } else {
- X (void) delwin(MenuWin);
- X (void) touchwin(stdscr);
- X return KEY_HOME;
- X }
- X case 'k':
- X case KEY_UP:
- X if (Menu->SelectedLine > 0) {
- X Menu->SelectedLine--;
- X } else {
- X InfoBoxOnScreen = 0;
- X (void) delwin(MenuWin);
- X (void) touchwin(stdscr);
- X return -2;
- X }
- X if (InfoBoxOnScreen) {
- X ShowMenu(Menu, MenuWin);
- X (void) wrefresh(MenuWin);
- X goto key_info; /* sorry */
- X }
- X break;
- X case 'j':
- X case KEY_DOWN:
- X if (Menu->SelectedLine + 1 < Menu->HowManyItems) {
- X Menu->SelectedLine++;
- X if (Menu->SelectedLine - Menu->TopLineOnScreen >= COLS - 4) {
- X Menu->TopLineOnScreen++;
- X }
- X } else {
- X (void) beep();
- X }
- X if (InfoBoxOnScreen) {
- X ShowMenu(Menu, MenuWin);
- X (void) wrefresh(MenuWin);
- X goto key_info; /* sorry */
- X }
- X break;
- X case '$': /* last item */
- X Menu->SelectedLine = Menu->HowManyItems - 1;
- X break;
- X case 'h':
- X case KEY_LEFT:
- X (void) delwin(MenuWin);
- X (void) touchwin(stdscr);
- X return KEY_LEFT;
- X case 'l':
- X case KEY_RIGHT:
- X (void) delwin(MenuWin);
- X (void) touchwin(stdscr);
- X return KEY_RIGHT;
- X default:
- X (void) beep();
- X break;
- X }
- X }
- X}
- X
- X/* FindMenuWidth() returns the length of the longest item in the menu.
- X */
- Xint
- XFindMenuWidth(Menu)
- X t_Menu *Menu;
- X{
- X int line;
- X if (Menu->Width <= 0) {
- X /* Include the width of the name of the menu. I am not sure
- X * whether this is right, but it looks a bit odd if the menu
- X * box is narrower than the highlighted menu name on the Bar...
- X */
- X if (Menu->NameLength <= 0) Menu->NameLength = strlen(Menu->Name);
- X Menu->Width = Menu->NameLength;
- X
- X /* Now see if any of the items are wider... */
- X for (line = 0; line < Menu->HowManyItems; line++) {
- X /* Individual length entries... */
- X if (Menu->Items[line].NameLength == 0) {
- X Menu->Items[line].NameLength = strlen(Menu->Items[line].Name);
- X }
- X
- X /* Overall widest... */
- X if (Menu->Items[line].NameLength > Menu->Width) {
- X Menu->Width = Menu->Items[line].NameLength;
- X }
- X }
- X }
- X return Menu->Width;
- X}
- X
- XShowMenu(Menu, MenuWin)
- X t_Menu *Menu;
- X WINDOW *MenuWin;
- X{
- X int line;
- X int pos = 0;
- X register int i;
- X
- X /* It is possible to compile this code so that the menu bar-line is
- X * broken by the top item in a selected menu. See the comments at
- X * the start of this file, and in menu.h
- X */
- X#ifdef SAVEMENULINE
- X /* draw the box by hand, because the top line is a little special...
- X * SVR3V2 has a line drawing function mvwhline(), but it is very
- X * V.3.2 specific. Sigh.
- X */
- X for (i = 1; i <= Menu->Width + 2; i++) {
- X (void) mvwaddch(MenuWin, 0, i, ACS_HLINE);
- X }
- X
- X /* NOTE:
- X * the ACS_trbl characters are PC/vt100-style line characters,
- X * where the t,r,b and l can either be B for Blank or S for single;
- X * later versions of curses may also have D for double, etc.;
- X * hence a character with single lines joining left and top would
- X * be ACS_SBBS. with single lines. If you have double lines, it
- X * might be good to use them for the menu bar, so as to give
- X * Tools Pain *Where* When Whom
- X * ============+=======+=================
- X * | Hands |
- X * | Feet |
- X * | etc. |
- X * +-------+
- X */
- X
- X /* T-pieces to join the menuline to the verticals of the menu */
- X (void) mvwaddch(MenuWin, 0, 0, ACS_BSSS);
- X /* The +3 in the next call to mvwaddch() comes from
- X * +2 for the box and space on the left
- X * +2 for the box and space on the right
- X * -1 because things start at 0
- X */
- X (void) mvwaddch(MenuWin, 0, Menu->Width + 3, ACS_BSSS);
- X#else
- X /* top line gets overwritten... just add corners! */
- X (void) mvwaddch(MenuWin, 0, 0, ACS_BBSS);
- X /* See above for the +3 */
- X (void) mvwaddch(MenuWin, 0, Menu->Width + 3, ACS_BSSB);
- X#endif /*SAVEMENULINE*/
- X
- X if (Menu->TopLineOnScreen > Menu->HowManyItems) {
- X Menu->TopLineOnScreen = Menu->HowManyItems - (LINES - 3);
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X }
- X
- X if (Menu->SelectedLine < Menu->TopLineOnScreen) {
- X Menu->TopLineOnScreen = Menu->SelectedLine;
- X } else if (Menu->SelectedLine - Menu->TopLineOnScreen > LINES - 4) {
- X Menu->TopLineOnScreen = Menu->SelectedLine - (LINES - 4);
- X }
- X
- X /* Final sanity check */
- X if (Menu->TopLineOnScreen < 0) {
- X Menu->TopLineOnScreen = 0;
- X }
- X
- X /* Now the lines of the menu, one at a time */
- X for (line = 0; line < LINES; line++) {
- X char *p;
- X int w;
- X
- X if (line + VSO >= Menu->HowManyItems) break;
- X
- X p = ((Menu->Items)[line + VSO]).Name;
- X
- X /* A neat horizontal line on the left */
- X if (line+BL > 0) {
- X (void) mvwaddch(MenuWin, line+BL, 0, ACS_VLINE);
- X }
- X (void) mvwaddch(MenuWin, line+BL, 1, (chtype) ' ');
- X
- X /* line is {1..N}, Selected is {0..N-1}. This simplifies
- X * its use elsewhere, at the expense of making this routine
- X * a little more complex.
- X */
- X if (line + VSO == Menu->SelectedLine) {
- X (void) wattrset(MenuWin, A_STANDOUT);
- X }
- X
- X /* On terminals without standout mode, one could use stars:
- X * Tools Pain *Where* When Whom
- X * =============+=======+=================
- X * | Hands |
- X * |*Feet**|
- X * | etc. |
- X * +-------+
- X * I wonder how I can tell if standout mode is working?
- X */
- X
- X /* Add the actual menu item */
- X (void) mvwaddstr(MenuWin, line+BL, 2, p);
- X
- X /* check how long it was */
- X w = (Menu->Items)[line + VSO].NameLength;
- X
- X /* Add spaces where to pad it out
- X * These might be inverse video spaces. Of course, not all
- X * terminals make stand-out spaces different from
- X * ordinary ones. On really dumb ttys, could use '*' here
- X * instead of ' '.
- X */
- X
- X for (i = w; i <= Menu->Width; i++) {
- X (void) mvwaddch(MenuWin, line+BL, i + 2, (chtype)' ');
- X }
- X
- X /* Turn bold/inverse off */
- X if (line + VSO == Menu->SelectedLine) {
- X (void) wattrset(MenuWin, 0);
- X }
- X
- X /* The extra space is really defense against magic cookies.
- X * See terminfo/termcap manuals...
- X */
- X (void) mvwaddch(MenuWin, line+BL, i + 1, (chtype) ' ');
- X
- X /* And a neat vertical line on the right. */
- X if (line+BL > 0) {
- X (void) mvwaddch(MenuWin, line+BL, i + 2, (chtype) ACS_VLINE);
- X }
- X }
- X
- X /* draw a line along the bottom only if it all fitted */
- X if (Menu->HowManyItems - Menu->TopLineOnScreen <= LINES - 2) {
- X for (pos = i + 1; pos > 0; pos--) {
- X (void) mvwaddch(MenuWin, line+BL, pos, (chtype) ACS_HLINE);
- X }
- X /* Lower left and lower right corner pieces join up neatly;
- X * Curses uses a '+' sign if it or the tty is too old...
- X * But the vt100-style character looks much better.
- X */
- X (void) mvwaddch(MenuWin, line+BL, 0, ACS_LLCORNER);
- X (void) mvwaddch(MenuWin, line+BL, i + 2, ACS_LRCORNER);
- X }
- X}
- X
- Xint
- XShowInfo(String, MenuWin, Itlx, Itly)
- X char *String;
- X WINDOW *MenuWin;
- X int Itlx;
- X int Itly;
- X /* Itlx and Itly control the place at which the pop-up window
- X * pops up... the top left corner of the new window is at
- X * (Itlx, Itly). By default, this is as near to the selected
- X * item as possible.
- X * So, down a bit and to the right a little.
- X */
- X{
- X int RetVal = 0;
- X int ch;
- X t_StringBox *StringBox, *MakeStringBox();
- X
- X /* If there is no information given, say so! */
- X if (String == (char *) 0) {
- X String = "No more information";
- X }
- X
- X /* Call a function to calculate the derived parameters, create the
- X * window and put the text on it!
- X */
- X StringBox = MakeStringBox("Info", String, 0L);
- X if (Itlx < 0) Itlx = 0;
- X if (Itly < 0) Itly = 0;
- X StringBox->tlx = Itlx;
- X StringBox->tly = Itly;
- X
- X /* Try to ensure that as much of the box is on screen as possible;
- X * if the user wants to move it off-screen, that's up to it, but
- X * we can at least ensure that it starts off OK!
- X */
- X if (StringBox->tlx + StringBox->Width >= COLS) {
- X if ((StringBox->tlx = COLS - StringBox->Width) < 0) {
- X StringBox->tlx = 0;
- X }
- X }
- X if (StringBox->tly + StringBox->Height >= LINES - 3) {
- X if ((StringBox->tly = LINES - StringBox->Height) < MENUTOP) {
- X /* MENUTOP is defined in internal.h to be the first row
- X * on the screen below the menu bar.
- X */
- X StringBox->tly = MENUTOP;
- X }
- X }
- X
- X do {
- X /* Add the text. UseBold is set after the user asks for more help.
- X * As there isn't any more, perhaps he/she hasn't noticed the info
- X * box, so we highlight it.
- X * (this feature seems to have been deleted -- Lee)
- X */
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X if (MenuWin) (void) touchwin(MenuWin);
- X if (MenuWin) (void) wnoutrefresh(MenuWin);
- X ShowStringBox(StringBox);
- X (void) touchwin(StringBox->Window); /* now we're on top... */
- X (void) wrefresh(StringBox->Window);
- X ch = getch();
- X
- Xcase_place: /* ComeFrom lower down, resize/move/scroll */
- X
- X if (ch == '\r' || ch == '\n') ch = ' ';
- X
- X switch (ch) {
- X case '?': case 'x': case 'X': /* x for explain */
- X case 'i': case 'I': /* i for info */
- X case KEY_HELP:
- X (void) mvwaddch(StringBox->Window, 0, 0, (chtype) 'X');
- X (void) wnoutrefresh(StringBox->Window);
- X {
- X char *p =
- X"Info window:\n\
- XPress SPACE or Q when you are done.\n\
- XYou can Resize the window with R,\n\
- XScroll the text inside it with S,\n\
- Xand Move it with M.\n\
- XHOME will first home the text, and\n\
- Xthen put the window near the top\n\
- Xleft hand corner of the screen.\n\
- X\n\
- X[press SPACE to continue]";
- X ch = ShowInfo(p, StringBox->Window, StringBox->tly + 2,
- X StringBox->tlx + 2);
- X if (ch == ' ') ch = 'x';
- X else goto case_place; /* sigh */
- X }
- X break;
- X case 'm': /* Move window */
- X case 'M':
- X ch = MoveStringBox(StringBox, MenuWin);
- X if (ch == ' ') ch = 'x';
- X else goto case_place;
- X break;
- X case 'r':
- X case 'R':
- X /* Resize */
- X ch = ResizeStringBox(StringBox, MenuWin);
- X if (ch == ' ') ch = 'x';
- X else goto case_place;
- X break;
- X case 's':
- X case 'S':
- X /* Scroll */
- X ch = ScrollStringBox(StringBox, MenuWin);
- X if (ch == ' ') ch = 'x';
- X else goto case_place;
- X break;
- X case KEY_LEFT:
- X case 'h':
- X RetVal = KEY_LEFT;
- X ch = ' ';
- X break;
- X case 'H':
- X case KEY_HOME:
- X RetVal = KEY_HOME;
- X ch = ' ';
- X break;
- X case KEY_RIGHT:
- X case 'l':
- X RetVal = KEY_RIGHT;
- X ch = ' ';
- X break;
- X case 'k':
- X case KEY_UP:
- X RetVal = KEY_UP;
- X ch = ' ';
- X break;
- X case 'j':
- X case KEY_DOWN:
- X RetVal = KEY_DOWN;
- X ch = ' ';
- X break;
- X default:
- X (void) beep();
- X break;
- X case 'q':
- X case 'Q': /* quit */
- X case 'f':
- X case 'F': /* finish */
- X ch = ' ';
- X case ' ':
- X RetVal = ' ';
- X break;
- X }
- X } while (ch != EOF && ch != ' ');
- X /* Clean Up */
- X (void) delwin(StringBox->Window);
- X (void) free((char *) StringBox);
- X (void) touchwin(stdscr);
- X return RetVal;
- X}
- X
- @@@End of lq-text/src/menu/menu.c
- echo x - lq-text/src/menu/stringbox.c 1>&2
- sed 's/^X//' >lq-text/src/menu/stringbox.c <<'@@@End of lq-text/src/menu/stringbox.c'
- X/* Functions to deal with StringBoxes...
- X *
- X * $Header: /usr/src/cmd/lq-text/src/menu/RCS/stringbox.c,v 1.2 90/10/04 16:28:22 lee Rel1-10 $
- X *
- X * $Log: stringbox.c,v $
- X * Revision 1.2 90/10/04 16:28:22 lee
- X * SysV compat improved.
- X *
- X * Revision 1.1 90/08/29 21:50:55 lee
- X * Initial revision
- X *
- X * Revision 2.1 89/08/07 13:50:19 lee
- X * First fully working (V.3.2 only) release;
- X * this is the baseline for future development.
- X *
- X *
- X */
- X
- X#ifdef ultrix
- X# include <cursesX.h>
- X#else
- X# include <curses.h>
- X#endif
- X
- X#ifndef A_STANDOUT
- X# include "oldcurses.h"
- X#endif
- X
- X#include <malloc.h>
- X#include "menu.h"
- X#include "error.h"
- X#include "internal.h"
- X
- Xvoid SetStringBoxSize();
- X
- X/* SetStringSize() --
- X * Set *Height and *Width to the minimum dimensions which will
- X * hold the given String.
- X * String can contain embedded newlines and tabs.
- X */
- Xvoid
- XSetStringSize(String, Height, Width)
- X char *String;
- X short *Height, *Width;
- X{
- X int ThisLineWidth = 0;
- X register char *p;
- X
- X *Height = 0;
- X *Width = 0;
- X
- X if (!String || !*String) return;
- X
- X for (p = String; *p; p++) {
- X if (*p == '\n') {
- X if (ThisLineWidth > *Width) {
- X *Width = ThisLineWidth;
- X }
- X ThisLineWidth = 0;
- X ++*Height;
- X } else {
- X ThisLineWidth++; /* Tabs always cause motion */
- X if (*p == '\t') {
- X ThisLineWidth |= 7;
- X }
- X }
- X }
- X if (ThisLineWidth > 0) {
- X /* No trailing newline, so treat the partial line at the
- X * end as if it were complete.
- X */
- X if (ThisLineWidth > *Width) {
- X *Width = ThisLineWidth;
- X }
- X ++*Height;
- X }
- X}
- X
- X/* PutStringInBox is a replacement for waddstr() that treats
- X * newlines specially in order to facilitate scrolling.
- X * The string
- X * "I am a\nhappy boy"
- X * (assuming \n is actually a newline character)
- X * gets put into the window as
- X * +-----------
- X * | I am a
- X * | happy boy
- X * (assuming that the window is large enough).
- X * If HScrollPos were 3, and VScrollPos 1, you would get
- X * +-----------
- X * | py boy
- X */
- X
- X/* MakeStringBox() is called to create a StringBox. */
- X
- Xt_StringBox *
- XMakeStringBox(Name, String, Flags)
- X unsigned long Flags;
- X char *Name;
- X char *String;
- X{
- X t_StringBox *StringBox;
- X
- X if ((StringBox = new(t_StringBox)) == (t_StringBox *) 0) {
- X error(ERR_FATAL|ERR_INTERNAL, "Not enough memory to create StringBox");
- X /*NOTREACHED*/
- X }
- X StringBox->Name = Name;
- X /** StringBox->Flags = Flags;**/
- X StringBox->Window = (WINDOW *) 0;
- X StringBox->tlx = StringBox->tly = 0;
- X StringBox->HScrollPos = StringBox->VScrollPos = 0;
- X StringBox->String = String;
- X
- X SetStringBoxSize(StringBox);
- X
- X return StringBox;
- X}
- X
- X/* Put the string box on the screen */
- XShowStringBox(StringBox)
- X t_StringBox *StringBox;
- X{
- X register char *pp;
- X char *String = StringBox->String;
- X register int x = 1; /* start at (1, 1) */
- X int y = 1;
- X int AtStartOfLine = 1;
- X
- X if (StringBox->Window == (WINDOW *) 0) {
- X if ((StringBox->Window =
- X newwin(StringBox->Height, StringBox->Width,
- X StringBox->tly, StringBox->tlx)) == (WINDOW *) 0) {
- X
- X error(ERR_FATAL|ERR_INTERNAL,
- X "Not enough memory for StringBox window %dx%d",
- X StringBox->Height,
- X StringBox->Width);
- X }
- X }
- X /* Now we have a window of the right size in the right place... */
- X
- X /* If vertical scrolling is in use, check it's in range */
- X if (StringBox->VScrollPos < 0) {
- X StringBox->VScrollPos = 0;
- X } else if (StringBox->VScrollPos >= StringBox->HowManyLines) {
- X StringBox->VScrollPos = StringBox->HowManyLines - 1;
- X }
- X
- X /* Ignore the first VScrollPos lines: */
- X String = StringBox->String;
- X for (y = 0; y < StringBox->VScrollPos; y++) {
- X extern char *strchr();
- X
- X String = strchr(String, '\n');
- X /*CANTHAPPEN*/
- X if (*++String == '\0') {
- X /* Not enough lines in the buffer.... */
- X return;
- X }
- X }
- X
- X y = 1; /* start the text on row 1, after the box */
- X AtStartOfLine = 1;
- X for (pp = String; *pp; pp++) {
- X if (AtStartOfLine) {
- X int i;
- X
- X /* skip the initial portion of each line */
- X for (i = 0; i < StringBox->HScrollPos; i++) {
- X if (!*pp) {
- X pp--;
- X break;
- X } else if (*pp == '\n') {
- X break;
- X }
- X pp++;
- X }
- X }
- X AtStartOfLine = (*pp == '\n');
- X if (*pp == '\n') { /* end of line.... */
- X (void) wmove(StringBox->Window, y, x);
- X (void) wclrtoeol(StringBox->Window);
- X y++;
- X x = 1;
- X (void) wmove(StringBox->Window, y, x);
- X (void) wclrtoeol(StringBox->Window);
- X } else { /* not a newline */
- X if (*pp == '\t') {
- X x |= 7;
- X x++;
- X /* tabs always move. Also, we started
- X * at position 1, so increment after the x |= 7.
- X */
- X } else {
- X (void) mvwaddch(StringBox->Window, y, x, (chtype) *pp);
- X x++;
- X }
- X }
- X } /* end for */
- X (void) wclrtoeol(StringBox->Window);
- X (void) wattrset(StringBox->Window, 0);
- X
- X /* do the box second, in case the text over-ran */
- X (void) box(StringBox->Window, 0, 0);
- X if (StringBox->HScrollPos > 0) {
- X /* Put a symbol like | to show that the message can
- X * be scrolled to --+ the right by pressing the right-
- X * arrow or "l". |
- X */
- X (void) mvwaddch(StringBox->Window, 1, 0, ACS_SBSS);
- X }
- X
- X if (StringBox->StringWidth - StringBox->HScrollPos > StringBox->Width - 2) {
- X /* Put a symbol like | to show that the message can
- X * be scrolled to +-- the left by pressing the left-
- X * arrow or "h". | Also, the HOME key will move the
- X * text to the top left of the InfoWin, and put the window
- X * near the top left of the screen.
- X */
- X /* (the -1 is because numbering starts form zero) */
- X (void) mvwaddch(StringBox->Window, 1, StringBox->Width - 1, ACS_SSSB);
- X }
- X
- X /* If you can go up... */
- X if (StringBox->VScrollPos > 0) {
- X /* ACS_trbl */
- X (void) mvwaddch(StringBox->Window, 0, 1, ACS_SSBS);
- X }
- X
- X /* And if you can go down (the -2 is for the box): */
- X if (StringBox->HowManyLines >
- X StringBox->VScrollPos + StringBox->Height - 2) {
- X (void) mvwaddch(StringBox->Window, StringBox->Height - 1, 1, ACS_BSSS);
- X
- X }
- X}
- X
- XResizeStringBox(StringBox, MenuWin)
- X t_StringBox *StringBox;
- X WINDOW *MenuWin;
- X{
- X int ch;
- X int Changed = 0;
- X
- X do {
- X if (Changed) {
- X /* Recreate the window... */
- X (void) delwin(StringBox->Window);
- X StringBox->Window = (WINDOW *) 0;
- X ShowStringBox(StringBox);
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X if (MenuWin) (void) touchwin(MenuWin);
- X if (MenuWin) (void) wnoutrefresh(MenuWin);
- X (void) touchwin(StringBox->Window);
- X }
- X
- X Changed = 0;
- X
- X (void) mvwaddch(StringBox->Window, 0, 0, (chtype) 'R');
- X (void) wmove(StringBox->Window, StringBox->Height, StringBox->Width);
- X (void) wrefresh(StringBox->Window);
- X
- X ch = getch();
- X
- X switch(ch) {
- X case 'q': case 'Q':
- X case 'f': case 'F':
- X ch = ' ';
- X case ' ':
- X break;
- X case '?':
- X case 'x': case 'X':
- X case 'i': case 'I':
- X case KEY_HELP:
- X {
- X char *p =
- X"Resize window: use the arrow keys\n\
- Xto move the window about. You can\n\
- Xuse HOME, H, or the d key to set\n\
- Xthe window to the default size.\n\
- XPress SPACE when you are done.";
- X ch = ShowInfo(p, StringBox->Window, StringBox->tly + 2,
- X StringBox->tlx + 2);
- X if (ch == ' ') ch = 'x';
- X else continue;
- X }
- X break;
- X case KEY_LEFT:
- X case 'h':
- X if (StringBox->Width > 3) {
- X StringBox->Width--;
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case KEY_RIGHT:
- X case 'l':
- X if (StringBox->Width + StringBox->tlx < COLS - 1) {
- X StringBox->Width++;
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case KEY_DOWN:
- X case 'j':
- X if (StringBox->Height + StringBox->tly < LINES - 1) {
- X StringBox->Height++;
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case KEY_UP:
- X case 'k':
- X if (StringBox->Height > 3) {
- X StringBox->Height--;
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case KEY_HOME: case 'H':
- X case 'd': case 'D':
- X /* special case: restore to default size; may
- X * also move the box, if it wouldn't fit on the screen in
- X * the new size.
- X */
- X SetStringBoxSize(StringBox);
- X Changed = 1;
- X break;
- X case 's': case'S':
- X case 'm': case 'M': /* Sideways jump to other window functions... */
- X return ch;
- X default:
- X (void) beep();
- X break;
- X }
- X } while (ch != EOF && ch != ' ');
- X return ch;
- X}
- X
- XMoveStringBox(StringBox, MenuWin)
- X t_StringBox *StringBox;
- X WINDOW *MenuWin;
- X{
- X int ch;
- X int Changed = 0;
- X
- X do {
- X if (Changed) {
- X /* Recreate the window... */
- X (void) delwin(StringBox->Window);
- X StringBox->Window = (WINDOW *) 0;
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X if (MenuWin) (void) touchwin(MenuWin);
- X if (MenuWin) (void) wnoutrefresh(MenuWin);
- X ShowStringBox(StringBox);
- X }
- X
- X Changed = 0;
- X
- X (void) mvwaddch(StringBox->Window, 0, 0, (chtype) 'M');
- X (void) wmove(StringBox->Window, StringBox->Height, StringBox->Width);
- X (void) wrefresh(StringBox->Window);
- X
- X ch = getch();
- X
- X switch(ch) {
- X case 'q': case 'Q':
- X case 'f': case 'F':
- X ch = ' ';
- X case ' ':
- X break;
- X
- X case '?': case 'x': case 'X': /* x for explain */
- X case 'i': case 'I': /* i for info */
- X case KEY_HELP:
- X (void) mvwaddch(StringBox->Window, 0, 0, (chtype) 'X');
- X (void) wnoutrefresh(StringBox->Window);
- X {
- X char *p =
- X"Scrolling Text:\n\
- XUse the arrow keys (or h j k and l)\n\
- Xto move the window around.\n\
- XYou can use the HOME key (or H) to\n\
- Xmove it near the top left hand corner\n\
- Xof the screen.\n\
- XWhen you finish moving the window,\n\
- Xor if you want to resize it,\n\
- Xpress SPACE.\n\
- XAfter you have finished, you can\n\
- Xuse R to resize the window,\n\
- Xand S to scroll the text in it.\n\
- X\n\
- X[press SPACE to continue]";
- X ch = ShowInfo(p, StringBox->Window, StringBox->tly + 2,
- X StringBox->tlx + 2);
- X if (ch == ' ') ch = 'x';
- X else continue;
- X }
- X break;
- X case 'h':
- X case KEY_LEFT:
- X if (StringBox->tlx > 0) {
- X StringBox->tlx--;
- X (void) mvwin(StringBox->Window, StringBox->tly, StringBox->tlx);
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'l':
- X case KEY_RIGHT:
- X if (StringBox->tlx + StringBox->Width < COLS) {
- X StringBox->tlx++;
- X (void) mvwin(StringBox->Window, StringBox->tly, StringBox->tlx);
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'k':
- X case KEY_UP:
- X if (StringBox->tly > 2) {
- X --StringBox->tly;
- X (void) mvwin(StringBox->Window, StringBox->tly, StringBox->tlx);
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'j':
- X case KEY_DOWN:
- X if (StringBox->tly + StringBox->Height < COLS - 1) {
- X ++StringBox->tly;
- X (void) mvwin(StringBox->Window, StringBox->tly, StringBox->tlx);
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'H':
- X case KEY_HOME:
- X StringBox->tlx = 0;
- X StringBox->tly = 2;
- X (void) mvwin(StringBox->Window, StringBox->tly, StringBox->tlx);
- X Changed = 1;
- X break;
- X case 's': case'S':
- X case 'r': case 'R': /* Jump to other functions */
- X return ch;
- X default:
- X (void) beep();
- X }
- X } while (ch != EOF && ch != ' ');
- X return ch;
- X}
- X
- XScrollStringBox(StringBox, MenuWin)
- X t_StringBox *StringBox;
- X WINDOW *MenuWin;
- X{
- X int ch;
- X int Changed = 0;
- X
- X do {
- X if (Changed) {
- X /* Recreate the window... */
- X (void) delwin(StringBox->Window);
- X StringBox->Window = (WINDOW *) 0;
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X if (MenuWin) (void) touchwin(MenuWin);
- X if (MenuWin) (void) wnoutrefresh(MenuWin);
- X ShowStringBox(StringBox);
- X }
- X
- X Changed = 0;
- X
- X (void) mvwaddch(StringBox->Window, 0, 0, (chtype) 'S');
- X (void) wmove(StringBox->Window, StringBox->Height, StringBox->Width);
- X (void) wrefresh(StringBox->Window);
- X
- X ch = getch();
- X
- X switch(ch) {
- X case 'q': case 'Q':
- X case 'f': case 'F':
- X ch = ' ';
- X case ' ':
- X break;
- X
- X case '?': case 'x': case 'X': /* x for explain */
- X case 'i': case 'I': /* i for info */
- X case KEY_HELP:
- X (void) mvwaddch(StringBox->Window, 0, 0, (chtype) 'X');
- X (void) wnoutrefresh(StringBox->Window);
- X {
- X char *p =
- X"Scrolling Text:\n\
- XUse the arrow keys (or h j k and l)\n\
- Xto move the text within the window.\n\
- XYou can use the HOME key (or H) to\n\
- Xmove to the start of the text.\n\
- XWhen you finish scrolling the text,\n\
- Xor if you want to move or resize the\n\
- Xwindow, press SPACE.\n\
- X\n\
- X[press SPACE to continue]";
- X ch = ShowInfo(p, StringBox->Window, StringBox->tly + 2,
- X StringBox->tlx + 2);
- X if (ch == ' ') ch = 'x';
- X else continue;
- X }
- X break;
- X case 'h':
- X case KEY_LEFT:
- X /* Press |space to continue. |
- X * <-----------------------> DescLen
- X * <-------------------> InfoWidth
- X * <------> StringBox->HScrollPos
- X * (Not allowed to go further left than this)
- X */
- X if (StringBox->HScrollPos > 0) {
- X StringBox->HScrollPos--;
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'l':
- X case KEY_RIGHT:
- X if (StringBox->StringWidth - StringBox->HScrollPos >
- X StringBox->Width - 2) {
- X StringBox->HScrollPos++;
- X Changed = 1;
- X } else {
- X beep();
- X }
- X break;
- X case 'k':
- X case KEY_UP:
- X if (StringBox->VScrollPos) {
- X StringBox->VScrollPos--;
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'j':
- X case KEY_DOWN:
- X /* forbid the last line of the screen so as to avoid scrolling/
- X * bottom-right-corner hassle, and also to avoid obscuring
- X * soft function labels if they're there.
- X */
- X if (StringBox->Height - 2 + StringBox->VScrollPos <
- X StringBox->HowManyLines) {
- X StringBox->VScrollPos++;
- X Changed = 1;
- X } else {
- X (void) beep();
- X }
- X break;
- X case 'H':
- X case KEY_HOME:
- X /* Not testing for > 0 here means that if things get really
- X * screwed up and {H,V}ScrollPos gets -ve, HOME will set
- X * things right again. Of course, the user won't know
- X * that, but every little helps...
- X */
- X if (StringBox->HScrollPos || StringBox->VScrollPos) {
- X StringBox->HScrollPos = 0;
- X StringBox->VScrollPos = 0;
- X Changed = 1;
- X }
- X break;
- X case 'r': case 'R':
- X case 'm': case 'M': /* Jump to other functions: */
- X return ch;
- X default:
- X (void) beep();
- X }
- X } while (ch != EOF && ch != ' ');
- X return ch;
- X}
- X
- Xvoid
- XSetStringBoxSize(StringBox)
- X t_StringBox *StringBox;
- X{
- X /* Measure the text */
- X SetStringSize(StringBox->String, &(StringBox->Height), &(StringBox->Width));
- X StringBox->HowManyLines = StringBox->Height;
- X StringBox->StringWidth = StringBox->Width;
- X
- X /* Leave room for a box */
- X StringBox->Height += 2;
- X StringBox->Width += 2;
- X
- X /* Check it's not too wide */
- X if (StringBox->Width >= COLS) {
- X StringBox->Width = COLS - 4;
- X }
- X
- X /* Check it's not too tall */
- X if (StringBox->Height >= LINES - 4) {
- X StringBox->Height = LINES - 4;
- X }
- X
- X /* check it's not too thin */
- X if (StringBox->Width < 3) { /* tiny screen, or no text at all... */
- X StringBox->Width = 3;
- X }
- X
- X /* Check it's not too short */
- X if (StringBox->Height < 3) { /* tiny screen, or no text at all... */
- X StringBox->Height = 3;
- X }
- X
- X /* Check it's on the screen */
- X if (StringBox->tlx + StringBox->Width >= COLS) {
- X /* right adjust if it didn't fit */
- X StringBox->tlx = (COLS - StringBox->Width) - 1;
- X /* ASSERT: StringBox->tlx > 0 because StringBox->Width < COLS */
- X }
- X if (StringBox->tly + StringBox->Height >= LINES - 3) {
- X /* avoid the bottom line of the screen */
- X StringBox->tly = (LINES - 3) - StringBox->Height;
- X }
- X}
- X
- Xchar *
- XAskForString(Message, MaxLen, MenuWin, Itlx, Itly)
- X char *Message;
- X int MaxLen;
- X WINDOW *MenuWin;
- X int Itlx;
- X int Itly;
- X{
- X t_StringBox *Question;
- X char *Answer;
- X char *p;
- X char *Text;
- X int i;
- X int ch;
- X
- X /* ensure that we allow at least 1 char of input! */
- X if (MaxLen < 1) MaxLen = 1;
- X
- X if ((Text = malloc(strlen(Message) + MaxLen + 5)) == (char *) 0) {
- X error(ERR_FATAL|ERR_MEMORY, "Not enough mem for question \"%s\"\n",
- X Message);
- X }
- X
- X (void) sprintf(Text, "%s\n : ", Message);
- X p = Answer = &Text[strlen(Text)]; /* i.e. pointing to the \0 */
- X
- X /* Make a StringBox containing the question and a space for
- X * the answer
- X */
- X Question = MakeStringBox("Question", Text, (unsigned long) 0);
- X
- X /* add space for the answer... */
- X if (Question->Width < 5) Question->Width = 5;
- X
- X if (Itlx < 0) Itlx = 0;
- X if (Itly < 3) Itly = 3; /* avoid the menu bar */
- X
- X Question->tlx = Itlx;
- X Question->tly = Itly;
- X /* Itlx and Itly control the place at which the pop-up window
- X * pops up... the top left corner of the new window is at
- X * (Itlx, Itly). By default, this is as near to the selected
- X * item as possible.
- X * So, down a bit and to the right a little.
- X */
- X
- X /* display the StringBox and wait for an answer. If necessary,
- X * extend and then scroll the StringBox to make the answer fit
- X */
- X
- X do {
- X for (i = 0;
- X i - Question->HScrollPos < Question->Width - 2 && i < MaxLen;
- X i++) {
- X if (&Answer[i] >= p) {
- X Answer[i] = '_';
- X Answer[i + 1] = '\0';
- X }
- X }
- X
- X (void) touchwin(stdscr);
- X (void) wnoutrefresh(stdscr);
- X if (MenuWin) {
- X (void) touchwin(MenuWin);
- X (void) wnoutrefresh(MenuWin);
- X }
- X /* SetStringBoxSize(Question); /* in case the text has changed */
- X
- X ShowStringBox(Question);
- X
- X (void) touchwin(Question->Window); /* now we're on top... */
- X
- X /* the +7 is for the bar on the left of the window, the " : ",
- X * and an extra one to put the cursor where the *next* character
- X * will be, plus an unexplained fudge factor.
- X */
- X (void) move(Question->tly + Question->Height - 2,
- X Question->tlx + (p - Answer) - Question->HScrollPos + 4);
- X (void) wrefresh(Question->Window);
- X (void) move(Question->tly + Question->Height - 2,
- X Question->tlx + (p - Answer) - Question->HScrollPos + 4);
- X ch = getch();
- X
- X if (ch == KEY_F(1) || ch == '\r' || ch == '\n') break;
- X
- X /* Note: p always points to the point at which the next character
- X * to be typed would go, and *p is \0.
- X */
- X
- X switch (ch) {
- X case KEY_UP:
- X case KEY_LEFT:
- X case KEY_DOWN:
- X case KEY_RIGHT:
- X (void) MoveStringBox(Question, MenuWin);
- X break;
- X case KEY_HOME:
- X /* Resize */
- X (void) ResizeStringBox(Question, MenuWin);
- X break;
- X case '\b':
- X case 127:
- X case 255:
- X case -1:
- X if (p > Answer) {
- X *p = '\0';
- X --p;
- X if (Question->HScrollPos > 0) --Question->HScrollPos;
- X } else {
- X beep();
- X }
- X break;
- X case 'W' ^ 64: /* copntrol-W -- delete word */
- X *p = '_';
- X while (p > Answer && (*p == ' ' || *p == '/')) {
- X p--;
- X if (Question->HScrollPos > 0) --Question->HScrollPos;
- X }
- X while (p > Answer && *p != ' ' && *p != '/') {
- X p--;
- X if (Question->HScrollPos > 0) --Question->HScrollPos;
- X }
- X if (*p == '/' || *p == ' ') p++;
- X *p = '\0';
- X break;
- X case 'U' ^ 64:
- X case 'X' ^ 64:
- X p = Answer;
- X *p = '\0';
- X Question->HScrollPos = 0;
- X break;
- X default:
- X if (p - Answer >= MaxLen) {
- X beep();
- X } else {
- X *p++ = ch;
- X /* The magic number on the next line works as follows:
- X * | : here is me typing stuff__ |
- X * ^^^^ ^^
- X * So there are 6 characters, plus one for the cursor;
- X * (p - Answer) gives one fewer than needed, so we arrive
- X * at 8.
- X */
- X if (p - Answer + 7 - Question->HScrollPos >= Question->Width) {
- X Question->HScrollPos += 4;
- X }
- X }
- X }
- X } while (ch != EOF && ch != KEY_F(1));
- X /* Clean Up */
- X (void) delwin(Question->Window);
- X (void) touchwin(stdscr);
- X
- X if (p > Answer) {
- X *p = '\0';
- X --p;
- X }
- X
- X if (p == Answer) {
- X (void) free(Text);
- X return (char *) 0;
- X } else {
- X unsigned len = strlen(Answer);
- X (void) bcopy(Answer, Text, len + 1);
- X Text[len] = '\0';
- X return realloc(Text, len + 1);
- X }
- X /*NOTREACHED*/
- X}
- @@@End of lq-text/src/menu/stringbox.c
- echo end of part 09
- --
- Liam R. E. Quin, lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337
-