717 lines
23 KiB
C
717 lines
23 KiB
C
|
/* OpenDoors Online Software Programming Toolkit
|
||
|
* (C) Copyright 1991 - 1999 by Brian Pirie.
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
*
|
||
|
* File: ODPopUp.c
|
||
|
*
|
||
|
* Description: Implements od_popup_menu(), for displaying a menu in
|
||
|
* a window, allowing the user to make a selection using
|
||
|
* "hot keys" or by using arrow keys.
|
||
|
*
|
||
|
* Revisions: Date Ver Who Change
|
||
|
* ---------------------------------------------------------------
|
||
|
* Oct 13, 1994 6.00 BP New file header format.
|
||
|
* Dec 09, 1994 6.00 BP Standardized coding style.
|
||
|
* Jan 15, 1995 6.00 BP Free menu structure on menu destroy.
|
||
|
* Feb 02, 1995 6.00 BP Added od_yield() call in for(;;) loop.
|
||
|
* Aug 19, 1995 6.00 BP 32-bit portability.
|
||
|
* Nov 11, 1995 6.00 BP Removed register keyword.
|
||
|
* Nov 14, 1995 6.00 BP Change valid range of nLevel to 0-10.
|
||
|
* Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
|
||
|
* Nov 17, 1995 6.00 BP Use new input queue mechanism.
|
||
|
* Dec 12, 1995 6.00 BP Added entry, exit and kernel macros.
|
||
|
* Dec 23, 1995 6.00 BP Restore original color on exit.
|
||
|
* Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
|
||
|
* Jan 04, 1996 6.00 BP Use od_get_input().
|
||
|
* Jan 12, 1996 6.00 BP Claim exclusive use of arrow keys.
|
||
|
* Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep().
|
||
|
* Jan 31, 1996 6.00 BP Added timeout for od_get_input().
|
||
|
* Jan 31, 1996 6.00 BP Add ODPopupCheckForKey() wait param.
|
||
|
* Jan 31, 1996 6.00 BP Ignore left & right if !MENU_PULLDOWN.
|
||
|
* Feb 13, 1996 6.00 BP Added od_get_input() flags parameter.
|
||
|
* Feb 19, 1996 6.00 BP Changed version number to 6.00.
|
||
|
* Mar 03, 1996 6.10 BP Begin version 6.10.
|
||
|
* Aug 10, 2003 6.23 SH *nix support
|
||
|
*/
|
||
|
|
||
|
#define BUILDING_OPENDOORS
|
||
|
|
||
|
#include <ctype.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "OpenDoor.h"
|
||
|
#include "ODCore.h"
|
||
|
#include "ODGen.h"
|
||
|
#include "ODPlat.h"
|
||
|
#include "ODKrnl.h"
|
||
|
#include "ODStat.h"
|
||
|
|
||
|
|
||
|
/* Configurable od_popup_menu() parameters. */
|
||
|
|
||
|
/* Maximum menu level. */
|
||
|
#define MENU_LEVELS 11
|
||
|
|
||
|
/* Maximum number of items in a menu. */
|
||
|
#define MAX_MENU_ITEMS 21
|
||
|
|
||
|
/* Maximum width of any menu item. */
|
||
|
#define MAX_ITEM_WIDTH 76
|
||
|
|
||
|
|
||
|
/* Other manifest constants. */
|
||
|
#define NO_COMMAND -10
|
||
|
|
||
|
|
||
|
/* Local data types. */
|
||
|
|
||
|
/* Information on an individual menu item. */
|
||
|
typedef struct
|
||
|
{
|
||
|
char szItemText[MAX_ITEM_WIDTH + 1];
|
||
|
BYTE btKeyIndex;
|
||
|
} tMenuItem;
|
||
|
|
||
|
/* Information on a popup menu level. */
|
||
|
typedef struct
|
||
|
{
|
||
|
tMenuItem *paMenuItems;
|
||
|
BYTE btNumMenuItems;
|
||
|
BYTE btWidth;
|
||
|
BYTE btRight;
|
||
|
BYTE btBottom;
|
||
|
BYTE btCursor;
|
||
|
BYTE btLeft;
|
||
|
BYTE btTop;
|
||
|
WORD wFlags;
|
||
|
void *pWindow;
|
||
|
} tMenuLevelInfo;
|
||
|
|
||
|
|
||
|
/* Private variables. */
|
||
|
|
||
|
/* Array of information on each menu level. */
|
||
|
tMenuLevelInfo MenuLevelInfo[MENU_LEVELS];
|
||
|
|
||
|
/* Current menu settings. */
|
||
|
static BYTE btCorrectItem;
|
||
|
static INT nCommand;
|
||
|
static WORD wCurrentFlags;
|
||
|
static BYTE btCurrentNumMenuItems;
|
||
|
static INT nCurrentLevel;
|
||
|
|
||
|
|
||
|
/* Private helper functions used by od_popup_menu(). */
|
||
|
static void ODPopupCheckForKey(BOOL bWaitForInput);
|
||
|
static void ODPopupDisplayMenuItem(BYTE btLeft, BYTE btTop,
|
||
|
tMenuItem *paMenuItems, BYTE btItemIndex, BOOL bHighlighted, BYTE btWidth,
|
||
|
BOOL bPositionCursor);
|
||
|
|
||
|
|
||
|
/* ----------------------------------------------------------------------------
|
||
|
* od_popup_menu()
|
||
|
*
|
||
|
* Displays a popup menu on the local and remote screens.
|
||
|
*
|
||
|
* Parameters: pszTitle - Text to show as the window title of the popup menu.
|
||
|
* If no title is desired, this parameter should be set
|
||
|
* to either "" or NULL.
|
||
|
*
|
||
|
* pszText - String which contains the menu definition. In the
|
||
|
* menu definition string, individual menu items are
|
||
|
* separated by a pipe ('|') character, and hotkeys are
|
||
|
* proceeded by a carat ('^') character.
|
||
|
*
|
||
|
* nLeft - The 1-based column number of the upper right corner
|
||
|
* of the menu.
|
||
|
*
|
||
|
* nTop - The 1-based row number of the upper right corner of
|
||
|
* the menu.
|
||
|
*
|
||
|
* nLevel - Menu level, which must be a value between 0 and
|
||
|
* MENU_LEVELS.
|
||
|
*
|
||
|
* uFlags - One or more flags, combined by the bitwise or (|)
|
||
|
* operator.
|
||
|
*
|
||
|
* Return: POPUP_ERROR on error, POPUP_ESCAPE if user pressed the Escape
|
||
|
* key, POPUP_LEFT if the user choose to move to the next menu to
|
||
|
* the left, POPUP_RIGHT if the user choose to move to the next
|
||
|
* menu to the right, or a postive value if the user choose an item
|
||
|
* from the menu. In this case, the return value is the 1-based
|
||
|
* index of the selected menu item.
|
||
|
*/
|
||
|
ODAPIDEF INT ODCALL od_popup_menu(char *pszTitle, char *pszText, INT nLeft,
|
||
|
INT nTop, INT nLevel, WORD uFlags)
|
||
|
{
|
||
|
tMenuItem *paMenuItems = NULL;
|
||
|
BYTE btCount;
|
||
|
BYTE btWidth;
|
||
|
BYTE btRight;
|
||
|
BYTE btBottom;
|
||
|
BYTE btCursor;
|
||
|
BYTE btLeft;
|
||
|
BYTE btTop;
|
||
|
void *pWindow;
|
||
|
BYTE btBetweenSize;
|
||
|
BYTE btTitleSize;
|
||
|
BYTE btRemaining;
|
||
|
BYTE btLineCount;
|
||
|
INT16 nOriginalAttrib;
|
||
|
|
||
|
/* Log function entry if running in trace mode. */
|
||
|
TRACE(TRACE_API, "od_popup_menu()");
|
||
|
|
||
|
/* Initialize OpenDoors, if not already done. */
|
||
|
if(!bODInitialized) od_init();
|
||
|
|
||
|
OD_API_ENTRY();
|
||
|
|
||
|
/* Setup od_box_chars appropriately. */
|
||
|
if(od_control.od_box_chars[BOX_BOTTOM] == 0)
|
||
|
{
|
||
|
od_control.od_box_chars[BOX_BOTTOM] = od_control.od_box_chars[BOX_TOP];
|
||
|
}
|
||
|
if(od_control.od_box_chars[BOX_RIGHT] == 0)
|
||
|
{
|
||
|
od_control.od_box_chars[BOX_RIGHT] = od_control.od_box_chars[BOX_LEFT];
|
||
|
}
|
||
|
|
||
|
/* Store initial display color. */
|
||
|
nOriginalAttrib = od_control.od_cur_attrib;
|
||
|
|
||
|
|
||
|
/* check level bounds */
|
||
|
if(nLevel < 0 || nLevel > MENU_LEVELS)
|
||
|
{
|
||
|
od_control.od_error = ERR_LIMIT;
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
/* normalize level */
|
||
|
nCurrentLevel = nLevel;
|
||
|
|
||
|
if(MenuLevelInfo[nLevel].pWindow == NULL)
|
||
|
{
|
||
|
btLeft = nLeft;
|
||
|
btTop = nTop;
|
||
|
wCurrentFlags = uFlags;
|
||
|
|
||
|
if(pszText == NULL)
|
||
|
{
|
||
|
od_control.od_error = ERR_PARAMETER;
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
|
||
|
if(paMenuItems == NULL)
|
||
|
{
|
||
|
if((paMenuItems = malloc(sizeof(tMenuItem) * MAX_MENU_ITEMS)) == NULL)
|
||
|
{
|
||
|
od_control.od_error = ERR_PARAMETER;
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
}
|
||
|
MenuLevelInfo[nLevel].paMenuItems = paMenuItems;
|
||
|
|
||
|
btCurrentNumMenuItems = 0;
|
||
|
btWidth = 0;
|
||
|
btCount = 0;
|
||
|
nCommand = NO_COMMAND;
|
||
|
paMenuItems[0].btKeyIndex = 0;
|
||
|
while(*pszText && btCurrentNumMenuItems < MAX_MENU_ITEMS)
|
||
|
{
|
||
|
switch(*pszText)
|
||
|
{
|
||
|
case '|':
|
||
|
paMenuItems[btCurrentNumMenuItems++].szItemText[btCount]
|
||
|
= '\0';
|
||
|
if(btCount > btWidth) btWidth = btCount;
|
||
|
btCount = 0;
|
||
|
paMenuItems[btCurrentNumMenuItems].btKeyIndex = 0;
|
||
|
break;
|
||
|
|
||
|
case '^':
|
||
|
if(btCount < MAX_ITEM_WIDTH)
|
||
|
{
|
||
|
paMenuItems[btCurrentNumMenuItems].btKeyIndex = btCount;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if(btCount < MAX_ITEM_WIDTH)
|
||
|
{
|
||
|
paMenuItems[btCurrentNumMenuItems].szItemText[btCount++] =
|
||
|
*pszText;
|
||
|
}
|
||
|
}
|
||
|
++pszText;
|
||
|
}
|
||
|
|
||
|
/* If we were in the middle of a menu item when we encountered the end */
|
||
|
/* of the string, then it should form an additional menu entry. This */
|
||
|
/* handles the case of a menu string to no terminating | for the last */
|
||
|
/* entry. */
|
||
|
if(btCount != 0)
|
||
|
{
|
||
|
/* null-terminate current menu entry string */
|
||
|
paMenuItems[btCurrentNumMenuItems++].szItemText[btCount] = '\0';
|
||
|
|
||
|
/* If this is the widest entry, update he menu width appropriately */
|
||
|
if(btCount > btWidth) btWidth = btCount;
|
||
|
}
|
||
|
|
||
|
/* If the menu description string does not contain any menu items */
|
||
|
if(btCurrentNumMenuItems == 0)
|
||
|
{
|
||
|
/* Return with parameter error */
|
||
|
od_control.od_error = ERR_PARAMETER;
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
|
||
|
/* Adjust menu width to allow title to fit, if possible */
|
||
|
/* If a title string was passed, and that string is wider than widest */
|
||
|
/* menu entry ... */
|
||
|
if(pszTitle != NULL && strlen(pszTitle) + 2 > btWidth)
|
||
|
{
|
||
|
/* Then width of menu window should be large enough to allow up to */
|
||
|
/* the first 76 characters of the title to fit. */
|
||
|
btWidth = strlen(pszTitle) + 2 > MAX_ITEM_WIDTH
|
||
|
? MAX_ITEM_WIDTH : strlen(pszTitle) + 2;
|
||
|
}
|
||
|
|
||
|
/* Based on number and size of menu items, and width of title, */
|
||
|
/* determine the bottom, right and inside width of the menu. */
|
||
|
btBottom = btTop + btCurrentNumMenuItems + 1;
|
||
|
btRight = btLeft + btWidth + 3;
|
||
|
btBetweenSize = (btRight - btLeft) - 1;
|
||
|
|
||
|
/* If neither ANSI nor AVATAR mode is available, return with an error */
|
||
|
if(!(od_control.user_ansi || od_control.user_avatar))
|
||
|
{
|
||
|
od_control.od_error = ERR_NOGRAPHICS;
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
|
||
|
/* If menu would "fall off" edge of screen, return with an error */
|
||
|
if(btLeft < 1 || btTop < 1 || btRight > OD_SCREEN_WIDTH
|
||
|
|| btBottom > OD_SCREEN_HEIGHT || btRight - btLeft < 2
|
||
|
|| btBottom - btTop < 2)
|
||
|
{
|
||
|
od_control.od_error = ERR_PARAMETER;
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
|
||
|
/* Allocate space to store window information. If unable to allocate */
|
||
|
/* enough space, return with an error. */
|
||
|
if((pWindow = malloc((btRight - btLeft + 1) * 2
|
||
|
+ (btBottom - btTop + 1) * 160)) == NULL)
|
||
|
{
|
||
|
od_control.od_error = ERR_MEMORY;
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
|
||
|
/* Store contents of screen where memu will be drawn in the temporary */
|
||
|
/* buffer. */
|
||
|
if(!od_gettext(btLeft, btTop, btRight, btBottom, pWindow))
|
||
|
{
|
||
|
free(pWindow);
|
||
|
pWindow = NULL;
|
||
|
|
||
|
/* Note that od_error code has been set in od_gettext(). */
|
||
|
OD_API_EXIT();
|
||
|
return(POPUP_ERROR);
|
||
|
}
|
||
|
|
||
|
/* Determine number of characters of title to be displayed */
|
||
|
if(pszTitle == NULL)
|
||
|
{
|
||
|
btTitleSize = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if((btTitleSize = strlen(pszTitle)) > (btBetweenSize - 4))
|
||
|
{
|
||
|
btTitleSize = btBetweenSize - 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
od_set_cursor(btTop,btLeft);
|
||
|
od_set_attrib(od_control.od_menu_border_col);
|
||
|
od_putch(od_control.od_box_chars[BOX_UPPERLEFT]);
|
||
|
if(btTitleSize == 0)
|
||
|
{
|
||
|
od_repeat(od_control.od_box_chars[BOX_TOP], btBetweenSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
od_repeat(od_control.od_box_chars[BOX_TOP],
|
||
|
btRemaining = ((btBetweenSize - btTitleSize - 2) / 2));
|
||
|
od_set_attrib(od_control.od_menu_title_col);
|
||
|
od_putch(' ');
|
||
|
od_disp(pszTitle,btTitleSize, TRUE);
|
||
|
od_putch(' ');
|
||
|
od_set_attrib(od_control.od_menu_border_col);
|
||
|
od_repeat(od_control.od_box_chars[BOX_TOP],
|
||
|
(BYTE)(btBetweenSize - btRemaining - btTitleSize - 2));
|
||
|
}
|
||
|
od_putch(od_control.od_box_chars[BOX_UPPERRIGHT]);
|
||
|
|
||
|
btLineCount = btTop + 1;
|
||
|
btCorrectItem = 0;
|
||
|
ODPopupCheckForKey(FALSE);
|
||
|
btCursor = btCorrectItem;
|
||
|
for(btCount = 0; btCount < btCurrentNumMenuItems
|
||
|
&& btLineCount < btBottom; ++btCount)
|
||
|
{
|
||
|
ODPopupCheckForKey(FALSE);
|
||
|
if(nCommand != NO_COMMAND && !(wCurrentFlags & MENU_KEEP))
|
||
|
{
|
||
|
goto exit_now;
|
||
|
}
|
||
|
|
||
|
od_set_cursor(btLineCount,btLeft);
|
||
|
od_putch(od_control.od_box_chars[BOX_LEFT]);
|
||
|
od_set_attrib(od_control.od_menu_text_col);
|
||
|
|
||
|
if(btCount == btCursor)
|
||
|
{
|
||
|
ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCount,
|
||
|
TRUE, btWidth, FALSE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCount,
|
||
|
FALSE, btWidth, FALSE);
|
||
|
}
|
||
|
|
||
|
od_set_attrib(od_control.od_menu_border_col);
|
||
|
od_putch(od_control.od_box_chars[BOX_RIGHT]);
|
||
|
++btLineCount;
|
||
|
}
|
||
|
|
||
|
od_set_cursor(btBottom, btLeft);
|
||
|
od_putch(od_control.od_box_chars[BOX_LOWERLEFT]);
|
||
|
od_repeat(od_control.od_box_chars[BOX_BOTTOM], btBetweenSize);
|
||
|
od_putch(od_control.od_box_chars[BOX_LOWERRIGHT]);
|
||
|
od_set_cursor(btTop + 1, btLeft + 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
paMenuItems = MenuLevelInfo[nLevel].paMenuItems;
|
||
|
btCurrentNumMenuItems = MenuLevelInfo[nLevel].btNumMenuItems;
|
||
|
btWidth = MenuLevelInfo[nLevel].btWidth;
|
||
|
btRight = MenuLevelInfo[nLevel].btRight;
|
||
|
btBottom = MenuLevelInfo[nLevel].btBottom;
|
||
|
btLeft = MenuLevelInfo[nLevel].btLeft;
|
||
|
btTop = MenuLevelInfo[nLevel].btTop;
|
||
|
wCurrentFlags = MenuLevelInfo[nLevel].wFlags;
|
||
|
pWindow = MenuLevelInfo[nLevel].pWindow;
|
||
|
btCorrectItem = btCursor = MenuLevelInfo[nLevel].btCursor;
|
||
|
nCommand = NO_COMMAND;
|
||
|
|
||
|
if(uFlags & MENU_DESTROY)
|
||
|
{
|
||
|
nCommand = POPUP_ESCAPE;
|
||
|
goto destroy;
|
||
|
}
|
||
|
|
||
|
/* Otherwise, position flashing hardware cursor appropriately */
|
||
|
od_set_cursor(btTop + btCursor + 1, btLeft + 1);
|
||
|
}
|
||
|
|
||
|
/* Claim exclusive use of arrow keys. */
|
||
|
ODStatStartArrowUse();
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
ODPopupCheckForKey(TRUE);
|
||
|
if(btCorrectItem != btCursor)
|
||
|
{
|
||
|
ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCursor,
|
||
|
FALSE, btWidth, TRUE);
|
||
|
btCursor = btCorrectItem;
|
||
|
ODWaitDrain(25);
|
||
|
ODPopupCheckForKey(FALSE);
|
||
|
ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCursor,
|
||
|
TRUE, btWidth, TRUE);
|
||
|
}
|
||
|
|
||
|
if(nCommand != NO_COMMAND)
|
||
|
{
|
||
|
goto exit_now;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exit_now:
|
||
|
if((!(wCurrentFlags & MENU_KEEP)) || nCommand <= 0)
|
||
|
{
|
||
|
destroy:
|
||
|
od_puttext(btLeft, btTop, btRight, btBottom, pWindow);
|
||
|
free(pWindow);
|
||
|
MenuLevelInfo[nLevel].pWindow = NULL;
|
||
|
if(paMenuItems != NULL)
|
||
|
{
|
||
|
free(paMenuItems);
|
||
|
MenuLevelInfo[nLevel].paMenuItems = NULL;
|
||
|
}
|
||
|
}
|
||
|
else if(wCurrentFlags & MENU_KEEP)
|
||
|
{
|
||
|
MenuLevelInfo[nLevel].paMenuItems = paMenuItems;
|
||
|
MenuLevelInfo[nLevel].btNumMenuItems = btCurrentNumMenuItems;
|
||
|
MenuLevelInfo[nLevel].btWidth = btWidth;
|
||
|
MenuLevelInfo[nLevel].btRight = btRight;
|
||
|
MenuLevelInfo[nLevel].btBottom = btBottom;
|
||
|
MenuLevelInfo[nLevel].btCursor = btCursor;
|
||
|
MenuLevelInfo[nLevel].btLeft = btLeft;
|
||
|
MenuLevelInfo[nLevel].btTop = btTop;
|
||
|
MenuLevelInfo[nLevel].wFlags = wCurrentFlags;
|
||
|
MenuLevelInfo[nLevel].pWindow = pWindow;
|
||
|
}
|
||
|
|
||
|
/* Restore original display color. */
|
||
|
od_set_attrib(nOriginalAttrib);
|
||
|
|
||
|
/* Release exclusive use of arrow keys. */
|
||
|
ODStatEndArrowUse();
|
||
|
|
||
|
OD_API_EXIT();
|
||
|
return(nCommand);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ----------------------------------------------------------------------------
|
||
|
* ODPopupCheckForKey() *** PRIVATE FUNCTION ***
|
||
|
*
|
||
|
* Checks whether or not the user has pressed any key. If one or more keys
|
||
|
* have been pressed, then these keystrokes are processed. This function
|
||
|
* returns when no more keys are waiting in the inbound buffer, or when a key
|
||
|
* has been pressed that requires immediate action (such as the [ENTER] key).
|
||
|
*
|
||
|
* Parameters: bWaitForInput - Indicates whether this function should return
|
||
|
* immediately if no input is waiting (FALSE), or
|
||
|
* wait for the next input even before returning
|
||
|
* (TRUE).
|
||
|
*
|
||
|
* Return: void
|
||
|
*/
|
||
|
static void ODPopupCheckForKey(BOOL bWaitForInput)
|
||
|
{
|
||
|
BYTE btCount;
|
||
|
tODInputEvent InputEvent;
|
||
|
BOOL bDoneAnythingYet = FALSE;
|
||
|
|
||
|
/* Loop, processing keys. If a command has been selected, stop looping */
|
||
|
/* immediately. If there are no more keys waiting, stop looping */
|
||
|
while(nCommand == NO_COMMAND)
|
||
|
{
|
||
|
CALL_KERNEL_IF_NEEDED();
|
||
|
|
||
|
if(!od_get_input(&InputEvent, bWaitForInput && !bDoneAnythingYet
|
||
|
? OD_NO_TIMEOUT : 0, GETIN_NORMAL))
|
||
|
{
|
||
|
/* Return right away if no input event is waiting. */
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bDoneAnythingYet = TRUE;
|
||
|
|
||
|
if(InputEvent.EventType == EVENT_EXTENDED_KEY)
|
||
|
{
|
||
|
switch(InputEvent.chKeyPress)
|
||
|
{
|
||
|
case OD_KEY_UP:
|
||
|
up_arrow:
|
||
|
if(btCorrectItem == 0)
|
||
|
{
|
||
|
btCorrectItem = btCurrentNumMenuItems - 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
--btCorrectItem;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OD_KEY_DOWN:
|
||
|
down_arrow:
|
||
|
if(++btCorrectItem >= btCurrentNumMenuItems)
|
||
|
{
|
||
|
btCorrectItem = 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OD_KEY_LEFT:
|
||
|
left_arrow:
|
||
|
if(wCurrentFlags & MENU_PULLDOWN)
|
||
|
{
|
||
|
nCommand = POPUP_LEFT;
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OD_KEY_RIGHT:
|
||
|
right_arrow:
|
||
|
if(wCurrentFlags & MENU_PULLDOWN)
|
||
|
{
|
||
|
nCommand = POPUP_RIGHT;
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if(InputEvent.EventType == EVENT_CHARACTER)
|
||
|
{
|
||
|
if(InputEvent.chKeyPress == '\n' || InputEvent.chKeyPress == '\r')
|
||
|
{
|
||
|
nCommand = btCorrectItem + 1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
else if(InputEvent.chKeyPress == 27)
|
||
|
{
|
||
|
if(wCurrentFlags & MENU_ALLOW_CANCEL)
|
||
|
{
|
||
|
nCommand = POPUP_ESCAPE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
/* Check whether key is a menu "hot key" */
|
||
|
for(btCount = 0; btCount < btCurrentNumMenuItems; ++btCount)
|
||
|
{
|
||
|
if(toupper(MenuLevelInfo[nCurrentLevel].paMenuItems[btCount]
|
||
|
.szItemText[MenuLevelInfo[nCurrentLevel].paMenuItems[btCount]
|
||
|
.btKeyIndex]) == toupper(InputEvent.chKeyPress))
|
||
|
{
|
||
|
btCorrectItem = btCount;
|
||
|
nCommand = btCorrectItem + 1;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* At this point, we know that key was not one of the "hot keys" */
|
||
|
/* Check for 4, 6, 8 and 2 keys as arrow keys. */
|
||
|
if(InputEvent.chKeyPress == '4')
|
||
|
{
|
||
|
goto left_arrow;
|
||
|
}
|
||
|
else if(InputEvent.chKeyPress == '6')
|
||
|
{
|
||
|
goto right_arrow;
|
||
|
}
|
||
|
else if(InputEvent.chKeyPress == '8')
|
||
|
{
|
||
|
goto up_arrow;
|
||
|
}
|
||
|
else if(InputEvent.chKeyPress == '2')
|
||
|
{
|
||
|
goto down_arrow;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ----------------------------------------------------------------------------
|
||
|
* ODPopupDisplayMenuItem() *** PRIVATE FUNCTION ***
|
||
|
*
|
||
|
* Displays an individual menu item.
|
||
|
*
|
||
|
* Parameters: btLeft - Column number where the menu item will be
|
||
|
* displayed.
|
||
|
*
|
||
|
* btTop - Row number where the menu item will be
|
||
|
* displayed.
|
||
|
*
|
||
|
* paMenuItems - Pointer to array of available menu items.
|
||
|
*
|
||
|
* btItemIndex - Index into paMenuItems of the menu item that
|
||
|
* is to be displayed.
|
||
|
*
|
||
|
* bHighlighted - TRUE if the items is to be displayed as
|
||
|
* highlighted, FALSE if it is to be displayed as
|
||
|
* non-highlighted.
|
||
|
*
|
||
|
* btWidth - Width of the menu item, in characters.
|
||
|
*
|
||
|
* bPositionCursor - TRUE if the cursor needs to be positioned
|
||
|
* prior to drawing the menu item, FALSE if the
|
||
|
* cursor is already in the required position.
|
||
|
*
|
||
|
* Return: void
|
||
|
*/
|
||
|
static void ODPopupDisplayMenuItem(BYTE btLeft, BYTE btTop,
|
||
|
tMenuItem *paMenuItems, BYTE btItemIndex, BOOL bHighlighted, BYTE btWidth,
|
||
|
BOOL bPositionCursor)
|
||
|
{
|
||
|
BYTE btCount;
|
||
|
char *pchItemText;
|
||
|
BYTE btKeyPosition;
|
||
|
BYTE btTextColor;
|
||
|
BYTE btKeyColor;
|
||
|
|
||
|
/* Check that parameters are reasonable when operating in debug mode. */
|
||
|
ASSERT(paMenuItems != NULL);
|
||
|
ASSERT(btItemIndex < MAX_MENU_ITEMS);
|
||
|
ASSERT(btWidth < OD_SCREEN_WIDTH);
|
||
|
|
||
|
++btLeft;
|
||
|
++btTop;
|
||
|
|
||
|
btTextColor = bHighlighted ? od_control.od_menu_highlight_col
|
||
|
: od_control.od_menu_text_col;
|
||
|
btKeyColor = bHighlighted ? od_control.od_menu_highkey_col
|
||
|
: od_control.od_menu_key_col;
|
||
|
|
||
|
pchItemText = (char *)(paMenuItems[btItemIndex].szItemText);
|
||
|
btKeyPosition = paMenuItems[btItemIndex].btKeyIndex;
|
||
|
|
||
|
if(bPositionCursor) od_set_cursor(btTop + btItemIndex, btLeft);
|
||
|
|
||
|
od_set_attrib(btTextColor);
|
||
|
od_putch(' ');
|
||
|
|
||
|
for(btCount = 0; btCount < btWidth && *pchItemText; ++btCount)
|
||
|
{
|
||
|
if(btCount == btKeyPosition)
|
||
|
{
|
||
|
od_set_attrib(btKeyColor);
|
||
|
od_putch(*pchItemText++);
|
||
|
od_set_attrib(btTextColor);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
od_putch(*pchItemText++);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
od_repeat(' ', (BYTE)((btWidth - btCount) + 1));
|
||
|
|
||
|
if(bPositionCursor) od_set_cursor(btTop + btItemIndex, btLeft);
|
||
|
}
|