2000-02-25 10:15:17 +00:00
|
|
|
// This may look like C code, but it is really -*- C++ -*-
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// The Goldware Library
|
|
|
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
|
|
|
// Copyright (C) 1999-2000 Alexander S. Aganichev
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Library 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
|
|
|
|
// Library General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Library General Public
|
|
|
|
// License along with this program; if not, write to the Free
|
|
|
|
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
// MA 02111-1307, USA
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// $Id$
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// Based on CXL by Mike Smedley.
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// wmenubeg() starts a menu definition
|
|
|
|
// wmenuitem() defines a menu item
|
|
|
|
// wmenuend() ends a menu definition
|
|
|
|
// wmenuget() processes the defined menu
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include <gctype.h>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <gmemdbg.h>
|
|
|
|
#include <gkbdcode.h>
|
|
|
|
#include <gkbdbase.h>
|
|
|
|
#include <gmoubase.h>
|
|
|
|
#include <gvidall.h>
|
|
|
|
#include <gwinall.h>
|
|
|
|
#include <gwinhelp.h>
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int _finaltagid;
|
|
|
|
|
|
|
|
int gmnudropthrough = NO;
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// prototypes for local functions
|
|
|
|
|
|
|
|
static _item_t* down_item(_item_t *curr);
|
|
|
|
static _item_t* left_item(_item_t *curr);
|
|
|
|
static _item_t* right_item(_item_t *curr);
|
|
|
|
static _item_t* up_item(_item_t *curr);
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// menu item movement definitions
|
|
|
|
|
|
|
|
#define ITM_LT 0
|
|
|
|
#define ITM_RT 1
|
|
|
|
#define ITM_UP 2
|
|
|
|
#define ITM_DN 3
|
|
|
|
#define ITM_FR 4
|
|
|
|
#define ITM_LS 5
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// array of function pointers to some of the item movement functions
|
|
|
|
|
|
|
|
static _item_t *(*mnu_funcs[4])(_item_t *) = {
|
|
|
|
left_item,
|
|
|
|
right_item,
|
|
|
|
up_item,
|
|
|
|
down_item
|
|
|
|
};
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// flag used for initial display of menu selections
|
|
|
|
|
|
|
|
static int dispdesc=YES;
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will calculate the width of the selection bar
|
|
|
|
|
|
|
|
static int calc_bar_width(_menu_t *wmenu,_item_t *witem)
|
|
|
|
{
|
|
|
|
register int width;
|
|
|
|
|
|
|
|
width=strlen(witem->str);
|
|
|
|
if(wmenu->barwidth) width=wmenu->barwidth;
|
|
|
|
return(width);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will calculate the window column
|
|
|
|
// at the center of the given menu item
|
|
|
|
|
|
|
|
static int calc_center_item(_item_t *item)
|
|
|
|
{
|
|
|
|
return( ((int)item->wcol) + (strlen(item->str)/2) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will hide the mouse cursor
|
|
|
|
// if mouse cursor mode is on
|
|
|
|
|
|
|
|
static void hide_mouse_cursor_mnu(void) {
|
|
|
|
|
|
|
|
#ifdef GOLD_MOUSE
|
|
|
|
if(gmou.FreeCursor())
|
|
|
|
gmou.HideCursor();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will display the mouse
|
|
|
|
// cursor if mouse cursor mode is on
|
|
|
|
|
|
|
|
static void show_mouse_cursor_mnu(void) {
|
|
|
|
|
|
|
|
#ifdef GOLD_MOUSE
|
|
|
|
if(gmou.FreeCursor()) {
|
|
|
|
gmou.ShowCursor();
|
|
|
|
gmou.SetCursor(0,0xFFFF,((LGREY|_LGREY)<<8));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function calls the given function
|
|
|
|
|
|
|
|
static void mnu_call_func(VfvCP func) {
|
|
|
|
|
|
|
|
_menu_t *menu;
|
|
|
|
int w;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
hide_mouse_cursor_mnu();
|
|
|
|
menu=gwin.cmenu;
|
|
|
|
w=whandle();
|
|
|
|
err=whelpush();
|
|
|
|
(*func)();
|
|
|
|
wactiv(w);
|
|
|
|
if(!err) whelpop();
|
|
|
|
gwin.cmenu=menu;
|
|
|
|
show_mouse_cursor_mnu();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will call a menu item's "after" function if it exists
|
|
|
|
|
|
|
|
static void call_after(_item_t *citem)
|
|
|
|
{
|
|
|
|
if(citem->after!=NULL)
|
|
|
|
mnu_call_func(citem->after);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will call a menu item's "before" function if it exists
|
|
|
|
|
|
|
|
static void call_before(_item_t *citem)
|
|
|
|
{
|
|
|
|
if(citem->before!=NULL)
|
|
|
|
mnu_call_func(citem->before);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function closes the current menu's window and reactivates
|
|
|
|
// the menu window open prior to opening the current menu window
|
|
|
|
|
|
|
|
static void close_window(int w)
|
|
|
|
{
|
|
|
|
if(!gwin.cmenu->usecurr) {
|
|
|
|
hide_mouse_cursor_mnu();
|
|
|
|
wclose();
|
|
|
|
wactiv(w);
|
|
|
|
show_mouse_cursor_mnu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function displays a menu selection, using selection bar if specified
|
|
|
|
|
|
|
|
static void disp_item(_item_t *witem,int bar)
|
|
|
|
{
|
|
|
|
char ch;
|
|
|
|
int chattr;
|
|
|
|
_wrec_t* whp;
|
|
|
|
char buf[256];
|
|
|
|
register const char* p;
|
|
|
|
register vatch* ptr=(vatch*)buf;
|
|
|
|
int i, textend,width,wcol,found=NO;
|
|
|
|
|
|
|
|
// if mouse cursor is on, temporarily hide it
|
|
|
|
hide_mouse_cursor_mnu();
|
|
|
|
|
|
|
|
// initialize width of output and end of text
|
|
|
|
p = witem->str;
|
|
|
|
width = calc_bar_width(gwin.cmenu,witem);
|
|
|
|
textend = gwin.cmenu->textpos+strlen(p)-1;
|
|
|
|
wgotoxy(witem->wrow,wcol=witem->wcol);
|
|
|
|
|
|
|
|
// display menu item including selection bar
|
|
|
|
for(i=0; i<width; i++) {
|
|
|
|
|
|
|
|
// see if currently in bar region. if so, then use
|
|
|
|
// a space for the character. otherwise use the
|
|
|
|
// character from the current position in the string
|
|
|
|
ch = (i<gwin.cmenu->textpos||i>textend)?' ':(*p++);
|
|
|
|
|
|
|
|
// select attribute of character to be displayed based upon if
|
|
|
|
// selection bar was specified, if the menu item is non-selectable,
|
|
|
|
// if the character is a tag character, or none of the above.
|
|
|
|
if(bar)
|
|
|
|
chattr = gwin.cmenu->barattr;
|
|
|
|
else if(witem->fmask&M_NOSEL)
|
|
|
|
chattr = gwin.cmenu->noselattr;
|
|
|
|
else if((ch==witem->schar)&&!found) {
|
|
|
|
found = YES;
|
|
|
|
chattr = gwin.cmenu->scharattr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
chattr = gwin.cmenu->textattr;
|
|
|
|
|
|
|
|
// display character in selected attribute
|
|
|
|
//wprintc(witem->wrow,wcol++,chattr,ch);
|
|
|
|
|
|
|
|
// Build menu line buffer
|
|
|
|
|
|
|
|
*ptr++ = vcatch(ch,chattr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display complete buffer
|
|
|
|
wprintws(witem->wrow, wcol, (vatch*)buf, width);
|
|
|
|
|
|
|
|
// display text description, if one exists
|
|
|
|
if(witem->desc!=NULL&&dispdesc) {
|
|
|
|
whp = wfindrec(witem->dwhdl);
|
|
|
|
i = (1 + whp->ecol - whp->scol) - (whp->border ? 2 : 0);
|
|
|
|
sprintf(buf, "%-*.*s", i, i, witem->desc);
|
|
|
|
wwprints(witem->dwhdl, witem->dwrow, witem->dwcol, witem->dattr, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if mouse cursor is hidden, unhide it
|
|
|
|
show_mouse_cursor_mnu();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function finds the next menu selection down
|
|
|
|
|
|
|
|
static _item_t * down_item(_item_t *curr)
|
|
|
|
{
|
|
|
|
_item_t *best,*temp;
|
|
|
|
int brow,bcol,tcol,trow,crow,ccol,tdist,bdist;
|
|
|
|
|
|
|
|
// initialize best record to NULL
|
|
|
|
best=NULL;
|
|
|
|
brow=bcol=32767;
|
|
|
|
|
|
|
|
// calculate window column at center of current item
|
|
|
|
crow=(int)curr->wrow;
|
|
|
|
ccol=calc_center_item(curr);
|
|
|
|
|
|
|
|
// search backwards through linked list, testing each item
|
|
|
|
for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) {
|
|
|
|
|
|
|
|
// calculate window column at center of test item
|
|
|
|
trow=(int)temp->wrow;
|
|
|
|
tcol=calc_center_item(temp);
|
|
|
|
|
|
|
|
if(trow>crow) {
|
|
|
|
tdist=abs((ccol-tcol));
|
|
|
|
bdist=abs((ccol-bcol));
|
|
|
|
if((trow<brow)||((trow==brow&&tdist<bdist))) {
|
|
|
|
best=temp;
|
|
|
|
brow=trow;
|
|
|
|
bcol=tcol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there wasn't an item downwards, then wrap around
|
|
|
|
if(best==NULL) {
|
|
|
|
if((temp=(_item_t*)throw_malloc(sizeof(_item_t)))==NULL) {
|
|
|
|
best=curr;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*temp=*curr;
|
|
|
|
temp->wrow=-1;
|
|
|
|
best=down_item(temp);
|
|
|
|
throw_free(temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
// see if menu selection is non-selectable
|
|
|
|
if(best->fmask&M_NOSEL)
|
|
|
|
best=down_item(best);
|
|
|
|
|
|
|
|
// return best record
|
|
|
|
return(best);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function finds the upper-leftmost menu selection
|
|
|
|
|
|
|
|
static _item_t * first_item(void)
|
|
|
|
{
|
|
|
|
_item_t *best,*temp;
|
|
|
|
|
|
|
|
// initialize best record to highest record in linked list
|
|
|
|
best=gwin.cmenu->item;
|
|
|
|
|
|
|
|
// search backwards through linked list, testing each item
|
|
|
|
for(temp=best->prev;temp!=NULL;temp=temp->prev) {
|
|
|
|
if( (temp->wrow<best->wrow) ||
|
|
|
|
( (temp->wrow==best->wrow) && (temp->wcol<best->wcol) ) )
|
|
|
|
best=temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// see if menu selection is non-selectable
|
|
|
|
if(best->fmask&M_NOSEL) best=right_item(best);
|
|
|
|
|
|
|
|
// return best record
|
|
|
|
return(best);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this is a recursive function that frees a menu and all of its submenus
|
|
|
|
|
|
|
|
static void free_menu(_menu_t *wmenu)
|
|
|
|
{
|
|
|
|
_item_t *witem;
|
|
|
|
|
|
|
|
// free all items in menu, including sub-menus
|
|
|
|
while(wmenu->item!=NULL) {
|
|
|
|
if(wmenu->item->child!=NULL) free_menu((_menu_t*)wmenu->item->child);
|
|
|
|
witem=wmenu->item->prev;
|
|
|
|
throw_free(wmenu->item);
|
|
|
|
wmenu->item=witem;
|
|
|
|
if(wmenu->item!=NULL) wmenu->item->next=NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// free the menu itself
|
|
|
|
throw_free(wmenu);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will find the bottom-rightmost menu selection
|
|
|
|
|
|
|
|
static _item_t * last_item(void)
|
|
|
|
{
|
|
|
|
_item_t *best,*temp;
|
|
|
|
int bcol;
|
|
|
|
|
|
|
|
// initialize best record to highest record in linked list
|
|
|
|
best=gwin.cmenu->item;
|
|
|
|
bcol=best->wcol;
|
|
|
|
|
|
|
|
// search backwards through linked list, testing each item
|
|
|
|
for(temp=best->prev;temp!=NULL;temp=temp->prev) {
|
|
|
|
if( (temp->wrow>best->wrow) ||
|
|
|
|
( (temp->wrow==best->wrow) &&
|
|
|
|
(temp->wcol>bcol) ) ) {
|
|
|
|
best=temp;
|
|
|
|
bcol=best->wcol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// see if menu selection is non-selectable
|
|
|
|
if(best->fmask&M_NOSEL) best=left_item(best);
|
|
|
|
|
|
|
|
// return best record
|
|
|
|
return(best);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function is called after a menu bar move
|
|
|
|
|
|
|
|
static void post_move(_item_t *citem)
|
|
|
|
{
|
|
|
|
gwin.cmenu->citem=citem;
|
|
|
|
gwin.help=citem->help;
|
|
|
|
disp_item(citem,1);
|
|
|
|
call_before(citem);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function prepares for a menu bar move
|
|
|
|
|
|
|
|
static void pre_move(_item_t *citem)
|
|
|
|
{
|
|
|
|
disp_item(citem,0);
|
|
|
|
call_after(citem);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function moves the selection bar to another menu item,
|
|
|
|
// automatically taking care of necessary pre/post move actions
|
|
|
|
|
|
|
|
static _item_t * goto_item(_item_t *citem,int which)
|
|
|
|
{
|
|
|
|
_item_t *item;
|
|
|
|
|
|
|
|
if(which==ITM_FR) item=first_item();
|
|
|
|
else if(which==ITM_LS) item=last_item();
|
|
|
|
else item=(*mnu_funcs[which])(citem);
|
|
|
|
if(item!=citem) {
|
|
|
|
pre_move(citem);
|
|
|
|
post_move(citem=item);
|
|
|
|
}
|
|
|
|
return(citem);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will find the menu selection to the left of current
|
|
|
|
|
|
|
|
static _item_t * left_item(_item_t *curr)
|
|
|
|
{
|
|
|
|
_item_t *best,*temp;
|
|
|
|
int wwidth,bpos,tpos,cpos;
|
|
|
|
|
|
|
|
// calculate window width and current position
|
|
|
|
wwidth=gwin.cmenu->ecol - gwin.cmenu->scol + 1;
|
|
|
|
cpos=(curr->wrow * wwidth) + curr->wcol;
|
|
|
|
|
|
|
|
// initialize best record to NULL, and best position to -1
|
|
|
|
best=NULL;
|
|
|
|
bpos=-1;
|
|
|
|
|
|
|
|
// search backwards through linked list, testing each item
|
|
|
|
for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) {
|
|
|
|
|
|
|
|
// calculate position of test each item
|
|
|
|
tpos=(temp->wrow*wwidth) + temp->wcol;
|
|
|
|
|
|
|
|
// compare position of test item with best item, current item
|
|
|
|
if(tpos>bpos && tpos<cpos) {
|
|
|
|
best=temp;
|
|
|
|
bpos=tpos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there wasn't a item to the left, then wrap around
|
|
|
|
if(best==NULL)
|
|
|
|
best=last_item();
|
|
|
|
else
|
|
|
|
// see if menu selection is non-selectable
|
|
|
|
if(best->fmask&M_NOSEL)
|
|
|
|
best=left_item(best);
|
|
|
|
|
|
|
|
// return best record
|
|
|
|
return(best);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function determines if the mouse cursor is on a menu item
|
|
|
|
|
|
|
|
#ifdef GOLD_MOUSE
|
|
|
|
static _item_t *mouse_on_item(_menu_t *menu,int mcrow,int mccol)
|
|
|
|
{
|
|
|
|
int srow,scol,border,start,end;
|
|
|
|
_item_t *item,*found;
|
|
|
|
|
|
|
|
found = NULL;
|
|
|
|
srow = menu->srow;
|
|
|
|
scol = menu->scol;
|
|
|
|
border = menu->btype==5?0:1;
|
|
|
|
for(item=menu->item;item!=NULL;item=item->prev) {
|
|
|
|
if(mcrow==(srow+border+item->wrow)) {
|
|
|
|
start = scol+border+item->wcol;
|
|
|
|
end = start+calc_bar_width(menu,item)-1;
|
|
|
|
if(mccol>=start&&mccol<=end) {
|
|
|
|
found=item;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(found);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
static void pre_exit(int w,int close)
|
|
|
|
{
|
|
|
|
_menu_t *wmenu;
|
|
|
|
|
|
|
|
hide_mouse_cursor_mnu();
|
|
|
|
|
|
|
|
// if not using current window for menu, then close it
|
|
|
|
if(close) close_window(w);
|
|
|
|
|
|
|
|
// if at highest menu then free the whole menu structure
|
|
|
|
if(gwin.cmenu==gwin.menu) {
|
|
|
|
wmenu=gwin.menu->prev;
|
|
|
|
if(gwin.cmenu!=NULL)
|
|
|
|
free_menu(gwin.cmenu);
|
|
|
|
gwin.menu=wmenu;
|
|
|
|
if(gwin.menu!=NULL)
|
|
|
|
gwin.menu->next=NULL;
|
|
|
|
gwin.cmenu=gwin.menu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function reads the mouse for input
|
|
|
|
|
|
|
|
static gkey read_mouse(_item_t* citem) {
|
|
|
|
|
|
|
|
#ifdef GOLD_MOUSE
|
|
|
|
register _item_t *item;
|
|
|
|
|
|
|
|
// if free-floating mouse cursor support is on
|
|
|
|
if(gmou.FreeCursor()) {
|
|
|
|
|
|
|
|
// clear mouse button queue
|
|
|
|
gmou.ClearEvents();
|
|
|
|
|
|
|
|
// loop until a key is pressed
|
|
|
|
while(!kbxhit() and gkbd.kbuf==NULL) {
|
|
|
|
|
|
|
|
// call the keyboard loop function
|
|
|
|
//if(gkbd.kbloop!=NULL)
|
|
|
|
//(*gkbd.kbloop)();
|
|
|
|
|
|
|
|
// if left button was pressed, and mouse cursor is on
|
|
|
|
// a selectable menu item, then move selection bar to
|
|
|
|
// that item, and select it. If mouse cursor is on
|
|
|
|
// a main menu item of a pull-down menu system, then
|
|
|
|
// stuff that item's selection character into the CXL
|
|
|
|
// keyboard buffer and return Esc to close the current
|
|
|
|
// pull-down menu.
|
|
|
|
gmou.GetLeftRelease();
|
|
|
|
if(gmou.Count()) {
|
|
|
|
item = mouse_on_item(gwin.cmenu,gmou.Row(),gmou.Column());
|
|
|
|
if(item == NULL) {
|
|
|
|
if(gwin.cmenu->menutype&M_PD) {
|
|
|
|
item = mouse_on_item(gwin.cmenu->parent,gmou.Row(),gmou.Column());
|
|
|
|
if(item and (!(item->fmask&M_NOSEL))) {
|
|
|
|
kbput(item->schar);
|
|
|
|
return Key_Esc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(!(item->fmask&M_NOSEL)) {
|
|
|
|
if(citem != item) {
|
|
|
|
pre_move(citem);
|
|
|
|
gwin.cmenu->citem = citem = item;
|
|
|
|
post_move(item);
|
|
|
|
}
|
|
|
|
return Key_Ent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if right button was pressed, simulate pressing the Esc key
|
|
|
|
gmou.GetRightRelease();
|
|
|
|
if(gmou.Count())
|
|
|
|
return Key_Esc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// return zero - it means a key was pressed
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function will find the menu selection to the right of current
|
|
|
|
|
|
|
|
static _item_t * right_item(_item_t *curr)
|
|
|
|
{
|
|
|
|
_item_t *best,*temp;
|
|
|
|
int wwidth,bpos,tpos,cpos;
|
|
|
|
|
|
|
|
// calculate window width and current position
|
|
|
|
wwidth=gwin.cmenu->ecol - gwin.cmenu->scol + 1;
|
|
|
|
cpos=(curr->wrow * wwidth) + curr->wcol;
|
|
|
|
|
|
|
|
// initialize best record to NULL, and best position to 32767
|
|
|
|
best=NULL;
|
|
|
|
bpos=32767;
|
|
|
|
|
|
|
|
// search backwards through linked list, testing items
|
|
|
|
for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) {
|
|
|
|
|
|
|
|
// calculate position of test item
|
|
|
|
tpos=(temp->wrow*wwidth) + temp->wcol;
|
|
|
|
|
|
|
|
// compare position of test item with best item, current item
|
|
|
|
if(tpos<bpos && tpos>cpos) {
|
|
|
|
best=temp;
|
|
|
|
bpos=tpos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there wasn't a item to the right, then wrap around
|
|
|
|
if(best==NULL)
|
|
|
|
best=first_item();
|
|
|
|
else
|
|
|
|
// see if menu selection is non-selectable
|
|
|
|
if(best->fmask&M_NOSEL)
|
|
|
|
best=right_item(best);
|
|
|
|
|
|
|
|
// return best record
|
|
|
|
return(best);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// this function finds the previous menu selection upwards
|
|
|
|
|
|
|
|
static _item_t * up_item(_item_t *curr)
|
|
|
|
{
|
|
|
|
_item_t *best,*temp;
|
|
|
|
int brow,bcol,tcol,crow,trow,ccol,tdist,bdist;
|
|
|
|
|
|
|
|
// initialize best record to NULL
|
|
|
|
best = NULL;
|
|
|
|
brow = -1;
|
|
|
|
bcol = 32767;
|
|
|
|
|
|
|
|
// calculate window column at center of current item
|
|
|
|
crow=(int)curr->wrow;
|
|
|
|
ccol=calc_center_item(curr);
|
|
|
|
|
|
|
|
// search backwards through linked list, testing items
|
|
|
|
for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) {
|
|
|
|
|
|
|
|
// calculate window column at center of test item
|
|
|
|
trow=(int)temp->wrow;
|
|
|
|
tcol=calc_center_item(temp);
|
|
|
|
|
|
|
|
if(trow<crow) {
|
|
|
|
tdist=abs(ccol-tcol);
|
|
|
|
bdist=abs(ccol-bcol);
|
|
|
|
if((trow>brow)||((trow==brow&&tdist<bdist))) {
|
|
|
|
best=temp;
|
|
|
|
brow=trow;
|
|
|
|
bcol=tcol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there wasn't a item to the left, then wrap around
|
|
|
|
if(best==NULL) {
|
|
|
|
if((temp=(_item_t*)throw_malloc(sizeof(_item_t)))==NULL) {
|
|
|
|
best=curr;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*temp=*curr;
|
|
|
|
temp->wrow=255;
|
|
|
|
best=up_item(temp);
|
|
|
|
throw_free(temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
// see if menu selection is non-selectable
|
|
|
|
if(best->fmask&M_NOSEL)
|
|
|
|
best=up_item(best);
|
|
|
|
|
|
|
|
// return best record
|
|
|
|
return(best);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenubeg(int srow, int scol, int erow, int ecol, int btype, int battr, int wattr, VfvCP open, int menutype) {
|
|
|
|
|
|
|
|
_menu_t* wmenu;
|
|
|
|
|
|
|
|
// if this is a submenu, then make sure that it is under a menu item
|
|
|
|
if(gwin.mlevel>gwin.ilevel) return(gwin.werrno=W_NOITMDEF);
|
|
|
|
|
|
|
|
// allocate memory for new menu record
|
|
|
|
if((wmenu=(_menu_t*)throw_malloc(sizeof(_menu_t)))==NULL)
|
|
|
|
return(gwin.werrno=W_ALLOCERR);
|
|
|
|
|
|
|
|
// if menu is not a submenu, make it a new base menu record
|
|
|
|
if(!gwin.mlevel) {
|
|
|
|
if(gwin.menu!=NULL) gwin.menu->next=wmenu;
|
|
|
|
wmenu->prev=gwin.menu;
|
|
|
|
wmenu->next=NULL;
|
|
|
|
wmenu->parent=NULL;
|
|
|
|
gwin.menu=gwin.cmenu=wmenu;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(menutype & M_PD)
|
|
|
|
gwin.cmenu->item->fmask |= M_HASPD; // Has a pull-down menu
|
|
|
|
gwin.cmenu->item->fmask &= ~M_CLOSE; // Don't close parent menu
|
|
|
|
wmenu->parent=gwin.cmenu;
|
|
|
|
gwin.cmenu = (_menu_t*)(gwin.cmenu->item->child = wmenu);
|
|
|
|
}
|
|
|
|
|
|
|
|
// save info in menu record
|
|
|
|
wmenu->srow=srow;
|
|
|
|
wmenu->scol=scol;
|
|
|
|
wmenu->erow=erow;
|
|
|
|
wmenu->ecol=ecol;
|
|
|
|
wmenu->btype=btype;
|
|
|
|
wmenu->battr=battr;
|
|
|
|
wmenu->loattr=battr;
|
|
|
|
wmenu->sbattr=battr;
|
|
|
|
wmenu->wattr=wattr;
|
|
|
|
wmenu->menutype=menutype;
|
|
|
|
wmenu->open=open;
|
|
|
|
wmenu->usecurr=NO;
|
|
|
|
wmenu->item=NULL;
|
|
|
|
wmenu->title = "";
|
|
|
|
wmenu->titlepos = -1;
|
|
|
|
wmenu->titleattr = 0;
|
|
|
|
wmenu->shadattr = -1;
|
|
|
|
wmenu->items = 0;
|
|
|
|
|
|
|
|
// increment menu level
|
|
|
|
gwin.mlevel++;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return(gwin.werrno=W_NOERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenuitem(int wrow, int wcol, const char* str, char schar, int tagid, int fmask, VfvCP select, gkey hotkey, int help) {
|
|
|
|
|
|
|
|
_item_t* witem;
|
|
|
|
|
|
|
|
// make sure that wmenubeg() or wmenubegc() has been called
|
|
|
|
if(!gwin.mlevel)
|
|
|
|
return (gwin.werrno=W_NOMNUBEG);
|
|
|
|
|
|
|
|
// allocate memory for new item record
|
|
|
|
witem = (_item_t*)throw_malloc(sizeof(_item_t));
|
|
|
|
if(witem==NULL)
|
|
|
|
return (gwin.werrno=W_ALLOCERR);
|
|
|
|
|
|
|
|
// add new menu item record to linked list
|
|
|
|
if(gwin.cmenu->item)
|
|
|
|
gwin.cmenu->item->next = witem;
|
|
|
|
witem->prev = gwin.cmenu->item;
|
|
|
|
witem->next = NULL;
|
|
|
|
gwin.cmenu->item = witem;
|
|
|
|
|
|
|
|
// save info in item record
|
|
|
|
witem->wrow = wrow;
|
|
|
|
witem->wcol = wcol;
|
|
|
|
witem->str = str;
|
|
|
|
witem->schar = schar;
|
|
|
|
witem->tagid = tagid;
|
|
|
|
witem->fmask = fmask;
|
|
|
|
witem->select = select;
|
|
|
|
witem->hotkey = hotkey;
|
|
|
|
witem->desc = NULL;
|
|
|
|
witem->dwhdl = -1;
|
|
|
|
witem->dwrow = 0;
|
|
|
|
witem->dwcol = 0;
|
|
|
|
witem->dattr = 0;
|
|
|
|
witem->redisp = NO;
|
|
|
|
witem->help = help;
|
|
|
|
witem->child = NULL;
|
|
|
|
witem->before = NULL;
|
|
|
|
witem->after = NULL;
|
|
|
|
|
|
|
|
gwin.cmenu->items++;
|
|
|
|
|
|
|
|
int border = (gwin.cmenu->btype == 5) ? 0 : 1;
|
|
|
|
|
|
|
|
int width = 1 + (gwin.cmenu->ecol-border) - (gwin.cmenu->scol+border);
|
|
|
|
size_t _titlen = gwin.cmenu->title ? strlen(gwin.cmenu->title) : 0;
|
2001-05-20 12:23:00 +00:00
|
|
|
size_t _strlen = strlen(str);
|
|
|
|
size_t length = maximum_of_two(_strlen, _titlen);
|
|
|
|
if((int)length > width)
|
2000-02-25 10:15:17 +00:00
|
|
|
gwin.cmenu->ecol += length - width;
|
|
|
|
|
|
|
|
if(gwin.cmenu->menutype & M_VERT) {
|
|
|
|
int height = 1 + (gwin.cmenu->erow-border) - (gwin.cmenu->srow+border);
|
|
|
|
if(gwin.cmenu->items > height)
|
|
|
|
gwin.cmenu->erow += gwin.cmenu->items - height;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set item level == menu level
|
|
|
|
gwin.ilevel = gwin.mlevel;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return (gwin.werrno=W_NOERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenuend(int taginit, int menutype, int barwidth, int textpos, int textattr, int scharattr, int noselattr, int barattr) {
|
|
|
|
|
|
|
|
_item_t* item;
|
|
|
|
int w_width, border, found;
|
|
|
|
|
|
|
|
// make sure at least 1 menu item has been defined
|
|
|
|
if(!gwin.mlevel||gwin.mlevel>gwin.ilevel)
|
|
|
|
return(gwin.werrno=W_NOITMDEF);
|
|
|
|
|
|
|
|
// make sure that the specified initial tagid matches the
|
|
|
|
// tagid of one of the defined menu items in this menu
|
|
|
|
for(found=NO,item=gwin.cmenu->item;item!=NULL;item=item->prev) {
|
|
|
|
if(item->tagid==taginit) {
|
|
|
|
found=YES;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!found) return(gwin.werrno=W_INVTAGID);
|
|
|
|
|
|
|
|
// if bar width > window width, then bar width = window width
|
|
|
|
border=(gwin.cmenu->btype==5)?0:1;
|
|
|
|
w_width=(gwin.cmenu->ecol-border)-(gwin.cmenu->scol+border)+1;
|
|
|
|
if(barwidth>w_width) barwidth=w_width;
|
|
|
|
|
|
|
|
// add rest of menu information to menu record
|
|
|
|
gwin.cmenu->citem = NULL;
|
|
|
|
gwin.cmenu->tagcurr = taginit;
|
|
|
|
gwin.cmenu->menutype |= menutype;
|
|
|
|
gwin.cmenu->barwidth = barwidth;
|
|
|
|
gwin.cmenu->textpos = barwidth?textpos:0;
|
|
|
|
gwin.cmenu->textattr = textattr;
|
|
|
|
gwin.cmenu->scharattr = scharattr;
|
|
|
|
gwin.cmenu->noselattr = noselattr;
|
|
|
|
gwin.cmenu->barattr = barattr;
|
|
|
|
|
|
|
|
// set current menu pointer to parent menu
|
|
|
|
if((gwin.cmenu=gwin.cmenu->parent)==NULL) gwin.cmenu=gwin.menu;
|
|
|
|
|
|
|
|
// decrement menu and item levels
|
|
|
|
gwin.mlevel--;
|
|
|
|
gwin.ilevel--;
|
|
|
|
|
|
|
|
// return with no error
|
|
|
|
return(gwin.werrno=W_NOERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenuget() {
|
|
|
|
|
|
|
|
int valid, pulldown=NO, menuerr, winerr, err;
|
|
|
|
_item_t* citem;
|
|
|
|
_item_t* item;
|
|
|
|
int w = -1;
|
|
|
|
gkey xch;
|
|
|
|
char ch;
|
|
|
|
static int _depth = 0;
|
|
|
|
|
|
|
|
if(_depth == 0)
|
|
|
|
_finaltagid = -1;
|
|
|
|
|
|
|
|
// make sure we have a defined menu
|
|
|
|
if(gwin.cmenu==NULL) {
|
|
|
|
gwin.werrno=W_NOMNUDEF;
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure that wmenuend() was called
|
|
|
|
if(gwin.mlevel||gwin.ilevel) {
|
|
|
|
gwin.werrno=W_NOMNUEND;
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// open menu's window (unless menu is to use current window)
|
|
|
|
if(!gwin.cmenu->usecurr) {
|
|
|
|
w=whandle();
|
|
|
|
hide_mouse_cursor_mnu();
|
|
|
|
if(!wopen(gwin.cmenu->srow,gwin.cmenu->scol,gwin.cmenu->erow,gwin.cmenu->ecol,gwin.cmenu->btype,gwin.cmenu->battr,gwin.cmenu->wattr,gwin.cmenu->sbattr,gwin.cmenu->loattr))
|
|
|
|
return -1;
|
|
|
|
if(gwin.cmenu->shadattr != -1)
|
|
|
|
wshadow((int)gwin.cmenu->shadattr);
|
|
|
|
if(gwin.cmenu->title and *gwin.cmenu->title)
|
|
|
|
wtitle(gwin.cmenu->title, gwin.cmenu->titlepos, gwin.cmenu->titleattr);
|
|
|
|
show_mouse_cursor_mnu();
|
|
|
|
|
|
|
|
// save environment info, call menu open
|
|
|
|
// function, then restore environment info
|
|
|
|
if(gwin.cmenu->open!=NULL)
|
|
|
|
mnu_call_func(gwin.cmenu->open);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if mouse cursor mode is on, show cursor
|
|
|
|
show_mouse_cursor_mnu();
|
|
|
|
|
|
|
|
// find first item in linked list
|
|
|
|
if((item=gwin.cmenu->item)!=NULL) for(;item->prev!=NULL;item=item->prev);
|
|
|
|
|
|
|
|
// display all menu items
|
|
|
|
dispdesc=NO;
|
|
|
|
valid=NO;
|
|
|
|
while(item!=NULL) {
|
|
|
|
disp_item(item,0);
|
|
|
|
if(!(item->fmask&M_NOSEL)) valid=YES;
|
|
|
|
item=item->next;
|
|
|
|
}
|
|
|
|
dispdesc=YES;
|
|
|
|
|
|
|
|
// make sure there is at least 1 selectable menu item
|
|
|
|
if(!valid) {
|
|
|
|
pre_exit(w,YES);
|
|
|
|
gwin.werrno=W_NOSELECT;
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// search linked list of item records for the item matching
|
|
|
|
// the last item. If there was no last item, search for
|
|
|
|
// the initial tag ID position. If no initial tag ID position
|
|
|
|
// was specified, then find the upper-leftmost menu item.
|
|
|
|
citem=NULL;
|
|
|
|
if(gwin.cmenu->menutype&M_SAVE) {
|
|
|
|
for(citem=gwin.cmenu->item;citem!=NULL;citem=citem->prev) {
|
|
|
|
if((gwin.cmenu->citem==citem)&&
|
|
|
|
(!(citem->fmask&M_NOSEL)))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(citem==NULL) {
|
|
|
|
citem=wmenuifind(gwin.cmenu->tagcurr);
|
|
|
|
if((citem==NULL)||(citem->fmask&M_NOSEL)) citem=first_item();
|
|
|
|
}
|
|
|
|
|
|
|
|
// call the current menu item's 'before'
|
|
|
|
// function and display current menu item
|
|
|
|
post_move(citem);
|
|
|
|
|
|
|
|
// main process of function
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
|
|
|
|
// update current menu item and help category
|
|
|
|
gwin.cmenu->citem=citem;
|
|
|
|
gwin.help=citem->help;
|
|
|
|
|
|
|
|
// read mouse/keyboard for keypress, then test the keypress
|
|
|
|
gkbd.inmenu=true;
|
|
|
|
xch = read_mouse(citem);
|
|
|
|
citem=gwin.cmenu->citem;
|
|
|
|
if(!xch) {
|
|
|
|
xch = getxch();
|
|
|
|
}
|
|
|
|
gkbd.inmenu=false;
|
|
|
|
switch(xch) {
|
|
|
|
|
|
|
|
case Key_Esc:
|
|
|
|
|
|
|
|
// if Esc checking is on, erase selection bar,
|
|
|
|
// free menu records and return to caller
|
|
|
|
if(gwin.esc||(gwin.cmenu!=gwin.menu)) {
|
|
|
|
ESCAPE_KEY:
|
|
|
|
pre_move(citem);
|
|
|
|
pre_exit(w,YES);
|
|
|
|
gwin.werrno=W_ESCPRESS;
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key_Home:
|
|
|
|
|
|
|
|
// hide selection bar and find upper-leftmost menu item
|
|
|
|
citem=goto_item(citem,ITM_FR);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key_Lft:
|
|
|
|
|
|
|
|
// if current menu is a pull-down menu,
|
|
|
|
// then erase selection bar, free menu records,
|
|
|
|
// and return special code to caller
|
|
|
|
if(gwin.cmenu->menutype&M_PD) {
|
|
|
|
pre_move(citem);
|
|
|
|
pre_exit(w,YES);
|
|
|
|
gwin.werrno=W_NOERROR;
|
|
|
|
return(M_PREVPD);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if current menu is a horizontal menu, then hide
|
|
|
|
// selection bar and find menu item to the left
|
|
|
|
if(gwin.cmenu->menutype&M_HORZ)
|
|
|
|
citem=goto_item(citem,ITM_LT);
|
|
|
|
|
|
|
|
// if pull-down menu flag is set, select this item
|
|
|
|
if(pulldown&&citem->child!=NULL) goto ENTER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key_Up:
|
|
|
|
|
|
|
|
// if current menu is a vertical menu, then hide
|
|
|
|
// selection bar and find menu item upwards
|
|
|
|
if(gwin.cmenu->menutype&(M_VERT|M_PD))
|
|
|
|
citem=goto_item(citem,ITM_UP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key_Rgt:
|
|
|
|
|
|
|
|
// if current menu is a pull-down menu,
|
|
|
|
// then erase selection bar, free menu records,
|
|
|
|
// and return special code to caller
|
|
|
|
if(gwin.cmenu->menutype&M_PD) {
|
|
|
|
pre_move(citem);
|
|
|
|
pre_exit(w,YES);
|
|
|
|
gwin.werrno=W_NOERROR;
|
|
|
|
return(M_NEXTPD);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if current menu is a horizontal menu, then hide
|
|
|
|
// selection bar and find menu item to the right
|
|
|
|
if(gwin.cmenu->menutype&M_HORZ)
|
|
|
|
citem=goto_item(citem,ITM_RT);
|
|
|
|
|
|
|
|
// if pulldown flag is set, then select this item
|
|
|
|
if(pulldown&&citem->child!=NULL) goto ENTER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key_Dwn:
|
|
|
|
|
|
|
|
// if current item has a pull-down menu, select it
|
|
|
|
if(citem->fmask&M_HASPD) goto ENTER;
|
|
|
|
|
|
|
|
// if current menu is a vertical menu, then hide
|
|
|
|
// selection bar and find menu item downwards
|
|
|
|
if(gwin.cmenu->menutype&(M_VERT|M_PD))
|
|
|
|
citem=goto_item(citem,ITM_DN);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key_End:
|
|
|
|
|
|
|
|
// hide selection bar and find
|
|
|
|
// lower-rightmost menu item
|
|
|
|
citem=goto_item(citem,ITM_LS);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key_Ent:
|
|
|
|
|
|
|
|
ENTER:
|
|
|
|
|
|
|
|
// if current menu item has a pull-down menu
|
|
|
|
// attached, then set the pulldown flag
|
|
|
|
if(citem->fmask&M_HASPD) pulldown=YES;
|
|
|
|
|
|
|
|
// display menu item with selection bar
|
|
|
|
disp_item(citem,1);
|
|
|
|
|
|
|
|
menuerr=0;
|
|
|
|
|
|
|
|
// if current menu item has a child menu
|
|
|
|
if(citem->child!=NULL) {
|
|
|
|
|
|
|
|
// save environment info, process child
|
|
|
|
// menu, then restore environment info
|
|
|
|
gwin.cmenu=(_menu_t*)citem->child;
|
|
|
|
hide_mouse_cursor_mnu();
|
|
|
|
err=whelpush();
|
|
|
|
_depth++;
|
|
|
|
menuerr=wmenuget();
|
|
|
|
_depth--;
|
|
|
|
winerr=gwin.werrno;
|
|
|
|
if(!err) whelpop();
|
|
|
|
show_mouse_cursor_mnu();
|
|
|
|
gwin.cmenu=gwin.cmenu->parent;
|
|
|
|
|
|
|
|
// if an error was returned by
|
|
|
|
// child menu, free menu records
|
|
|
|
// and pass error code to caller
|
|
|
|
if(menuerr==-1&&winerr!=W_ESCPRESS) {
|
|
|
|
call_after(citem);
|
|
|
|
menuerr=winerr;
|
|
|
|
pre_exit(w,YES);
|
|
|
|
gwin.werrno=menuerr;
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the M_CLOSB feature is on, then close the menu's
|
|
|
|
// window before the selection function is called.
|
|
|
|
if(citem->fmask&M_CLOSB) close_window(w);
|
|
|
|
|
|
|
|
// this is used as a flag to see if the selection bar's
|
|
|
|
// position has been changed by the select function.
|
|
|
|
gwin.cmenu->tagcurr=-1;
|
|
|
|
|
|
|
|
// if current menu item has a select function, call it
|
|
|
|
if(citem->select!=NULL)
|
|
|
|
mnu_call_func(citem->select);
|
|
|
|
|
|
|
|
// if the M_CLOSB feature is on, then free the current
|
|
|
|
// menu a before the selection function is called.
|
|
|
|
if(citem->fmask&M_CLOSB) {
|
|
|
|
call_after(citem);
|
|
|
|
_finaltagid = citem->tagid;
|
|
|
|
pre_exit(w,NO);
|
|
|
|
gwin.werrno=W_NOERROR;
|
|
|
|
return _finaltagid;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check all menu items in current menu to
|
|
|
|
// see if their redisplay flag has been set
|
|
|
|
for(item=gwin.cmenu->item;item!=NULL;item=item->prev) {
|
|
|
|
if(item->redisp) {
|
|
|
|
disp_item(item,(item==citem));
|
|
|
|
item->redisp=NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// see if selection bar position was changed by select
|
|
|
|
// function. if so, then move selection bar to new item
|
|
|
|
if(gwin.cmenu->tagcurr!=-1) {
|
|
|
|
item=wmenuifind(gwin.cmenu->tagcurr);
|
|
|
|
if(item!=NULL&&(!(item->fmask&M_NOSEL))) {
|
|
|
|
pre_move(citem);
|
|
|
|
post_move(gwin.cmenu->citem=citem=item);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if current menu item has a pull-down attached
|
|
|
|
if(citem->fmask&M_HASPD) {
|
|
|
|
|
|
|
|
// if child menu returned previous pull-down menu
|
|
|
|
// flag, find menu item to the left and select it
|
|
|
|
if(menuerr==M_PREVPD) {
|
|
|
|
citem=goto_item(citem,ITM_LT);
|
|
|
|
if(citem->fmask&M_HASPD) goto ENTER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if child menu returned next pull-down menu
|
|
|
|
// flag, find menu item to the right and select it
|
|
|
|
if(menuerr==M_NEXTPD) {
|
|
|
|
citem=goto_item(citem,ITM_RT);
|
|
|
|
if(citem->fmask&M_HASPD) goto ENTER;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// turn off pulldown flag
|
|
|
|
pulldown=NO;
|
|
|
|
|
|
|
|
// if child menu returned an exit-all-menus flag,
|
|
|
|
// then free menu records and pass exit-all-menus
|
|
|
|
// flag onto caller
|
|
|
|
if((menuerr==M_EXITALL)||(citem->fmask&M_CLALL)) {
|
|
|
|
disp_item(citem,1);
|
|
|
|
call_after(citem);
|
|
|
|
if(citem->fmask&M_CLALL)
|
|
|
|
if(_finaltagid == -1)
|
|
|
|
_finaltagid = citem->tagid;
|
|
|
|
pre_exit(w,YES);
|
|
|
|
gwin.werrno=W_NOERROR;
|
|
|
|
return M_EXITALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// unless an exit-this-menu flag was returned by the
|
|
|
|
// child menu, or current item has close-menu
|
|
|
|
// specified, free menu records, and return tag
|
|
|
|
// identifier of current menu item
|
|
|
|
if(citem->child!=NULL||citem->select!=NULL)
|
|
|
|
if((menuerr!=M_EXIT)&&(!(citem->fmask&M_CLOSE)))
|
|
|
|
break;
|
|
|
|
call_after(citem);
|
|
|
|
_finaltagid = citem->tagid;
|
|
|
|
pre_exit(w,YES);
|
|
|
|
gwin.werrno=W_NOERROR;
|
|
|
|
return _finaltagid;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
// separate ASCII code from keypress code, if ASCII
|
|
|
|
// code is zero, then it must be an extended key
|
|
|
|
ch=(char)xch;
|
|
|
|
if(!ch and gmnudropthrough) {
|
|
|
|
if((xch != Key_PgDn) and (xch != Key_PgUp))
|
|
|
|
kbput(xch);
|
|
|
|
goto ESCAPE_KEY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// scan through list of items for one that
|
|
|
|
// has a tag identifier matching keypress
|
|
|
|
valid=YES;
|
|
|
|
item=citem->next;
|
|
|
|
for(;;) {
|
|
|
|
while(item!=NULL) {
|
|
|
|
if((toupper(ch)==toupper(item->schar))&&(!(item->fmask
|
|
|
|
&M_NOSEL))) goto FARBREAK;
|
|
|
|
if(citem==item) {
|
|
|
|
valid=NO;
|
|
|
|
goto FARBREAK;
|
|
|
|
}
|
|
|
|
item=item->next;
|
|
|
|
}
|
|
|
|
for(item=gwin.cmenu->item;item->prev!=NULL;
|
|
|
|
item=item->prev);
|
|
|
|
}
|
|
|
|
|
|
|
|
FARBREAK:
|
|
|
|
|
|
|
|
// if a matching tag identifier was found,
|
|
|
|
// then hide selection bar, and if quick-key
|
|
|
|
// selection is allowed, select the found menu item
|
|
|
|
if(valid) {
|
|
|
|
if(item!=citem) {
|
|
|
|
pre_move(citem);
|
|
|
|
post_move(gwin.cmenu->citem=citem=item);
|
|
|
|
}
|
|
|
|
if(!(gwin.cmenu->menutype&M_NOQS)) goto ENTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// Starts a menu definition in active window
|
|
|
|
|
|
|
|
int wmenubegc() {
|
|
|
|
|
|
|
|
// call wmenubeg() using current window parameters
|
|
|
|
if(wmenubeg(gwin.active->srow,
|
|
|
|
gwin.active->scol,
|
|
|
|
gwin.active->erow,
|
|
|
|
gwin.active->ecol,
|
|
|
|
gwin.active->btype,
|
|
|
|
gwin.active->battr,
|
|
|
|
gwin.active->wattr,
|
|
|
|
NULL)) {
|
|
|
|
return gwin.werrno;
|
|
|
|
}
|
|
|
|
|
|
|
|
// turn on use-current-window flag
|
|
|
|
gwin.cmenu->usecurr=YES;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return gwin.werrno=W_NOERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
static _item_t* search_menu(_menu_t* menu, int tagid) {
|
|
|
|
|
|
|
|
_item_t *witem, *item;
|
|
|
|
|
|
|
|
// do while more items in this menu
|
|
|
|
for(witem=menu->item; witem!=NULL; witem=witem->prev) {
|
|
|
|
|
|
|
|
// if tagid of found item matches item we're
|
|
|
|
// searching for, then return that item's address
|
|
|
|
if(witem->tagid==tagid)
|
|
|
|
return witem;
|
|
|
|
|
|
|
|
// if current item has a child menu, search it
|
|
|
|
if(witem->child!=NULL) {
|
|
|
|
item = search_menu((_menu_t*)witem->child,tagid);
|
|
|
|
if(item!=NULL)
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// return address of item found
|
|
|
|
return witem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// Finds item record in a menu structure
|
|
|
|
|
|
|
|
_item_t* wmenuifind(int tagid) {
|
|
|
|
|
|
|
|
_item_t* item;
|
|
|
|
|
|
|
|
// check for existance of a menu
|
|
|
|
if(gwin.cmenu==NULL) {
|
|
|
|
gwin.werrno=W_NOMNUDEF;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// start search process at root of menu structure
|
|
|
|
item = search_menu(gwin.menu,tagid);
|
|
|
|
|
|
|
|
// return to caller
|
|
|
|
gwin.werrno = (item==NULL) ? W_NOTFOUND : W_NOERROR;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
// Adds a text description to menu item
|
|
|
|
|
|
|
|
int wmenuitxt(int whdl, int wrow, int wcol, int attr, const char* str) {
|
|
|
|
|
|
|
|
// make sure at least 1 menu item has been defined
|
|
|
|
if(!gwin.mlevel or gwin.mlevel>gwin.ilevel)
|
|
|
|
return gwin.werrno=W_NOITMDEF;
|
|
|
|
|
|
|
|
// add description info to menu record
|
|
|
|
_item_t* citem = gwin.cmenu->item;
|
|
|
|
citem->dwhdl = whdl;
|
|
|
|
citem->dwrow = wrow;
|
|
|
|
citem->dwcol = wcol;
|
|
|
|
citem->dattr = (int)attr;
|
|
|
|
citem->desc = str;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return gwin.werrno=W_NOERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenuiba(VfvCP before, VfvCP after) {
|
|
|
|
|
|
|
|
// make sure at least 1 menu item has been defined
|
|
|
|
if(!gwin.mlevel or gwin.mlevel > gwin.ilevel)
|
|
|
|
return(gwin.werrno=W_NOITMDEF);
|
|
|
|
|
|
|
|
// update menu item record
|
|
|
|
gwin.cmenu->item->before = before;
|
|
|
|
gwin.cmenu->item->after = after;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return (gwin.werrno=W_NOERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenuidsab(int tagid) {
|
|
|
|
|
|
|
|
struct _item_t *item;
|
|
|
|
|
|
|
|
// check for existance of a menu
|
|
|
|
if(gwin.cmenu==NULL)
|
|
|
|
return (gwin.werrno=W_NOMNUDEF);
|
|
|
|
|
|
|
|
// find address of requested menu item
|
|
|
|
if((item=wmenuifind(tagid))==NULL)
|
|
|
|
return gwin.werrno;
|
|
|
|
|
|
|
|
// disable menu item by making it nonselectable
|
|
|
|
item->fmask |= M_NOSEL;
|
|
|
|
|
|
|
|
// set menu item's redisplay flag
|
|
|
|
item->redisp = true;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return (gwin.werrno=W_NOERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenuienab(int tagid) {
|
|
|
|
|
|
|
|
struct _item_t *item;
|
|
|
|
|
|
|
|
// check for existance of a menu
|
|
|
|
if(gwin.cmenu==NULL)
|
|
|
|
return (gwin.werrno=W_NOMNUDEF);
|
|
|
|
|
|
|
|
// find address of requested menu item
|
|
|
|
if((item=wmenuifind(tagid))==NULL)
|
|
|
|
return gwin.werrno;
|
|
|
|
|
|
|
|
// enable menu item by making it selectable
|
|
|
|
item->fmask &= (~M_NOSEL);
|
|
|
|
|
|
|
|
// set menu item's redisplay flag
|
|
|
|
item->redisp = true;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return (gwin.werrno=W_NOERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
|
|
int wmenuinext(int tagid) {
|
|
|
|
|
|
|
|
// see if tagid is valid
|
|
|
|
if(wmenuifind(tagid)==NULL)
|
|
|
|
return gwin.werrno;
|
|
|
|
|
|
|
|
// set current menu's current tagid to input tagid
|
|
|
|
wmenumcurr()->tagcurr = tagid;
|
|
|
|
|
|
|
|
// return normally
|
|
|
|
return (gwin.werrno=W_NOERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|